hb-ot-shape-complex-indic.cc revision 8ef3d53255ae9fbb0e46c22909e50009d1e7eeb0
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" 28a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod#include "hb-ot-shape-private.hh" 2949c5ec51444f27f33e1eb6aa1959c61b08fa89c0Behdad Esfahbod#include "hb-ot-layout-private.hh" 30352372ae5ea0998e40cf9fe43c22b6b610a5764eBehdad Esfahbod 311d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 32a3e04bee2c2fa648759a87e460db6b4f1b685586Behdad Esfahbod#define OLD_INDIC_TAG(script) (((hb_tag_t) script) | 0x20000000) 33a3e04bee2c2fa648759a87e460db6b4f1b685586Behdad Esfahbod#define IS_OLD_INDIC_TAG(tag) ( \ 341d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_BENGALI) || \ 351d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_DEVANAGARI) || \ 361d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_GUJARATI) || \ 371d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_GURMUKHI) || \ 381d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_KANNADA) || \ 391d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_MALAYALAM) || \ 401d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_ORIYA) || \ 411d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_TAMIL) || \ 421d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod (tag) == OLD_INDIC_TAG (HB_SCRIPT_TELUGU) || \ 431d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 0) 441d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 451d002048d5afcd45abbb09fdf0419f13b2e2265cBehdad Esfahbod 46a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstruct indic_options_t 47ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod{ 48a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int initialized : 1; 49a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int uniscribe_bug_compatible : 1; 50a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 51a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 52a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodunion indic_options_union_t { 53a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod int i; 54a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_t opts; 55a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod}; 56a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad EsfahbodASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t)); 57a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 58a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodstatic indic_options_union_t 59a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options_init (void) 60a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 61a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod indic_options_union_t u; 62a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.i = 0; 63a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.initialized = 1; 64a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 65a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod char *c = getenv ("HB_OT_INDIC_OPTIONS"); 66a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); 67a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 68a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return u; 69a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 70a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 71a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodinline indic_options_t 72a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbodindic_options (void) 73a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod{ 74a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod static indic_options_union_t options; 75a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 76a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (unlikely (!options.i)) { 77a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod /* This is idempotent and threadsafe. */ 78a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod options = indic_options_init (); 79ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 80ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 81a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod return options.opts; 82a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod} 83a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod 84ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod 853614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbodstruct indic_shape_plan_t 86743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 873614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod struct would_apply_feature_t 88610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod { 893614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod would_apply_feature_t (const hb_ot_map_t *map, hb_tag_t feature_tag) 90610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod { 91610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod map->get_stage_lookups (0/*GSUB*/, 92610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod map->get_feature_stage (0/*GSUB*/, feature_tag), 93610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod &lookups, &count); 94610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod } 95610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod 96610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod inline bool would_substitute (hb_codepoint_t *glyphs, 97610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod unsigned int glyphs_count, 98610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod hb_face_t *face) const 99610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod { 100610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 101610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index)) 102610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod return true; 103610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod return false; 104610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod } 105610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod 106610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod private: 107610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod const hb_ot_map_t::lookup_map_t *lookups; 108610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod unsigned int count; 109610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod }; 110610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod 1113614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod indic_shape_plan_t (const hb_ot_map_t *map_) : 1123614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod map (map_), 1133614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod pref (map_, HB_TAG('p','r','e','f')), 1143614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod blwf (map_, HB_TAG('b','l','w','f')), 1153614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod pstf (map_, HB_TAG('p','s','t','f')), 1163614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod is_old_spec (IS_OLD_INDIC_TAG (map->get_chosen_script (0))) {} 117610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod 118610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod const hb_ot_map_t *map; 1193614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod would_apply_feature_t pref; 1203614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod would_apply_feature_t blwf; 1213614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod would_apply_feature_t pstf; 1223614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod bool is_old_spec; 123610e5e8f713bb2a68939b72cb2b801a7aaede4f9Behdad Esfahbod}; 124743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 125f055442716ec7543ed156d4789955b19c11a5255Behdad Esfahbodstatic indic_position_t 1268ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbodconsonant_position_from_font (const indic_shape_plan_t *indic_plan, 1278ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t *glyphs, unsigned int glyphs_len, 1288ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face) 129f055442716ec7543ed156d4789955b19c11a5255Behdad Esfahbod{ 1303614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C; 1313614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod if (indic_plan->blwf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_BELOW_C; 1323614ba242fc7d338761acdda365a134706035b6dBehdad Esfahbod if (indic_plan->pstf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) return POS_POST_C; 133f055442716ec7543ed156d4789955b19c11a5255Behdad Esfahbod return POS_BASE_C; 134743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 135743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1369ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 1379ccc6382ba43760167c134c18c1c4ada4b8c3f22Behdad Esfahbod 138eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstruct feature_list_t { 139c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_tag_t tag; 140c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod hb_bool_t is_global; 141eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 142eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 143d5c4edcdd6df32f2f23aca44f14838b4baab4d7aBehdad Esfahbod/* These features are applied one at a time, given the order in this table. */ 144eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 145eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodindic_basic_features[] = 146b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 147c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('n','u','k','t'), true}, 148e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod {HB_TAG('a','k','h','n'), true}, 149c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('r','p','h','f'), false}, 1501ac075b227090a9ad930dcc1670236c176b27067Behdad Esfahbod {HB_TAG('r','k','r','f'), true}, 151c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','r','e','f'), false}, 152c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('b','l','w','f'), false}, 153c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('h','a','l','f'), false}, 15429f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod {HB_TAG('a','b','v','f'), false}, 155c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod {HB_TAG('p','s','t','f'), false}, 1560201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod {HB_TAG('c','f','a','r'), false}, 15720b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod {HB_TAG('c','j','c','t'), true}, 1581d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod {HB_TAG('v','a','t','u'), true}, 159c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod}; 160c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod 161c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod/* Same order as the indic_basic_features array */ 162c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbodenum { 163c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod _NUKT, 164e0475345d5d7db8dbc8b554beedfa2435c5d7fd1Behdad Esfahbod _AKHN, 165c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod RPHF, 166df6d45c693c417bf311e6fa49f18a8558542e525Behdad Esfahbod _RKRF, 167c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PREF, 168c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod BLWF, 169c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod HALF, 17029f106d7fba25e1464debd3a4831a7380d75c4c9Behdad Esfahbod ABVF, 171c7fe56a1d5d3e969b6ec51cd9ecd471706a19568Behdad Esfahbod PSTF, 1720201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod CFAR, 17320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod _CJCT, 1741d6846db9ebf84561bb30a4e48c6c43184914099Behdad Esfahbod VATU 175b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod}; 176b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 177d5c4edcdd6df32f2f23aca44f14838b4baab4d7aBehdad Esfahbod/* These features are applied all at once. */ 178eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodstatic const feature_list_t 179eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbodindic_other_features[] = 180b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 181eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('i','n','i','t'), false}, 182eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('p','r','e','s'), true}, 183eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('a','b','v','s'), true}, 184eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('b','l','w','s'), true}, 185eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('p','s','t','s'), true}, 186eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('h','a','l','n'), true}, 187eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 188eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('d','i','s','t'), true}, 189eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('a','b','v','m'), true}, 190eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod {HB_TAG('b','l','w','m'), true}, 191eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod}; 192eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 193743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 194743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 195743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodinitial_reordering (const hb_ot_map_t *map, 196743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod hb_face_t *face, 197743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod hb_buffer_t *buffer, 198743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod void *user_data HB_UNUSED); 199f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodstatic void 200f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbodfinal_reordering (const hb_ot_map_t *map, 201f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod hb_face_t *face, 202f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod hb_buffer_t *buffer, 203743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod void *user_data HB_UNUSED); 204b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 205693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 206693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodcollect_features_indic (const hb_ot_complex_shaper_t *shaper, 207693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod hb_ot_map_builder_t *map, 208693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod const hb_segment_properties_t *props) 209b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 210f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('l','o','c','l')); 211a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod /* The Indic specs do not require ccmp, but we apply it here since if 212a54a5505a35eef5315a8e2e7a79502901e3eff5fBehdad Esfahbod * there is a use of it, it's typically at the beginning. */ 213f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_bool_feature (HB_TAG('c','c','m','p')); 214f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 215743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod map->add_gsub_pause (initial_reordering, NULL); 216f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 217412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) { 21876f76812ac7cca8ac6935952a2360d5e151480faBehdad Esfahbod map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global); 219412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod map->add_gsub_pause (NULL, NULL); 220412b91889d9a1ae477e8b6907d0b9a76e78a6c91Behdad Esfahbod } 221b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 222f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod map->add_gsub_pause (final_reordering, NULL); 223f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 224d5c4edcdd6df32f2f23aca44f14838b4baab4d7aBehdad Esfahbod for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++) 225eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod map->add_bool_feature (indic_other_features[i].tag, indic_other_features[i].is_global); 226b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 227b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 228693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 229693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodoverride_features_indic (const hb_ot_complex_shaper_t *shaper, 230693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod hb_ot_map_builder_t *map, 231693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod const hb_segment_properties_t *props) 232d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod{ 233af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod /* Uniscribe does not apply 'kern'. */ 234af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 235af92b4cc90e4184d5bdd8037c551ed482700114fBehdad Esfahbod map->add_feature (HB_TAG('k','e','r','n'), 0, true); 236d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod} 237d96838ef951ce6170eb2dc576ebcba2262cf7008Behdad Esfahbod 238867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 239693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 2408ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbodupdate_consonant_positions (const hb_ot_map_t *map, 2418ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_buffer_t *buffer, 2428ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_font_t *font) 2438ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod{ 2448ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t virama; 2458ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod switch ((int) buffer->props.script) { 2468ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_DEVANAGARI: virama = 0x094D; break; 2478ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_BENGALI: virama = 0x09CD; break; 2488ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_GURMUKHI: virama = 0x0A4D; break; 2498ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_GUJARATI: virama = 0x0ACD; break; 2508ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_ORIYA: virama = 0x0B4D; break; 2518ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_TAMIL: virama = 0x0BCD; break; 2528ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_TELUGU: virama = 0x0C4D; break; 2538ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_KANNADA: virama = 0x0CCD; break; 2548ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_MALAYALAM: virama = 0x0D4D; break; 2558ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_SINHALA: virama = 0x0DCA; break; 2568ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod case HB_SCRIPT_KHMER: virama = 0x17D2; break; 2578ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod default: virama = 0; break; 2588ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 2598ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 2608ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod indic_shape_plan_t indic_plan (map); 2618ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 2628ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int consonant_pos = indic_plan.is_old_spec ? 0 : 1; 2638ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_codepoint_t glyphs[2]; 2648ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (virama && font->get_glyph (virama, 0, &glyphs[1 - consonant_pos])) 2658ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod { 2668ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod hb_face_t *face = font->face; 2678ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod unsigned int count = buffer->len; 2688ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 2698ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod if (buffer->info[i].indic_position() == POS_BASE_C) { 2708ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod font->get_glyph (buffer->info[i].codepoint, 0, &glyphs[consonant_pos]); 2718ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod buffer->info[i].indic_position() = consonant_position_from_font (&indic_plan, glyphs, 2, face); 2728ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 2738ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod } 2748ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod} 2758ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod 2768ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbodstatic void 277693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodsetup_masks_indic (const hb_ot_complex_shaper_t *shaper, 278693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod const hb_ot_map_t *map, 279693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod hb_buffer_t *buffer, 280693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod hb_font_t *font) 281b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod{ 2829f9bcceca6321d5a5812f878de1de39901349a78Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); 2839f9bcceca6321d5a5812f878de1de39901349a78Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); 2849f9bcceca6321d5a5812f878de1de39901349a78Behdad Esfahbod 285743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* We cannot setup masks here. We save information about characters 286743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and setup masks later on in a pause-callback. */ 287743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 288743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod unsigned int count = buffer->len; 289b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 2903eb6f81fd3f1e56679eec10d08f5e2303121753fBehdad Esfahbod set_indic_properties (buffer->info[i]); 2913eb6f81fd3f1e56679eec10d08f5e2303121753fBehdad Esfahbod 2928ef3d53255ae9fbb0e46c22909e50009d1e7eeb0Behdad Esfahbod update_consonant_positions (map, buffer, font); 293743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 294b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 29545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbodstatic int 29645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbodcompare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 29745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod{ 29845d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod int a = pa->indic_position(); 29945d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod int b = pb->indic_position(); 30045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 30145d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 30245d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod} 303867361c3ad39629a8d5b7dc48d558a1c19e37d43Behdad Esfahbod 3047ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod/* Rules from: 3057ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ 3067ea58db311bfb0d8f804d1e9f4a1f004bd45075aBehdad Esfahbod 307743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 30870fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbodinitial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *basic_mask_array, 309ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 310743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 311ee58f3bc75d2d071a71b94063bf12205a5871acbBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 312743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 313617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod 314743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 1. Find base consonant: 315743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 316743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The shaping engine finds the base consonant of the syllable, using the 317743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following algorithm: starting from the end of the syllable, move backwards 318743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * until a consonant is found that does not have a below-base or post-base 319743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * form (post-base forms have to follow below-base forms), or that is not a 320743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * pre-base reordering Ra, or arrive at the first consonant. The consonant 321743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * stopped at will be the base. 322743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 323743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o If the syllable starts with Ra + Halant (in a script that has Reph) 324743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 325743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * base consonants. 326743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 327743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 3285e72071062c015237b79fbd0521341a63166a204Behdad Esfahbod unsigned int base = end; 32976b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod bool has_reph = false; 330743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 33176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod { 332617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 333617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 334617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * base consonants. */ 335617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod unsigned int limit = start; 33670fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod if (basic_mask_array[RPHF] && 337617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod start + 3 <= end && 338617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start].indic_category() == OT_Ra && 339617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod info[start + 1].indic_category() == OT_H && 340f31d97e44eeb6fb141f3de928e27e033fc7b1f47Behdad Esfahbod (unlikely (buffer->props.script == HB_SCRIPT_SINHALA || buffer->props.script == HB_SCRIPT_TELUGU) ? 341f31d97e44eeb6fb141f3de928e27e033fc7b1f47Behdad Esfahbod info[start + 2].indic_category() == OT_ZWJ /* In Sinhala & Telugu, form Reph only if ZWJ is present */: 3423285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod !is_joiner (info[start + 2] /* In other scripts, any joiner blocks Reph formation */ ) 3433285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod )) 344617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod { 345617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod limit += 2; 3463285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod while (limit < end && is_joiner (info[limit])) 3473285e107c9a83aeb552e67f9460680ff6d167d88Behdad Esfahbod limit++; 348617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod base = start; 349617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = true; 350617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod }; 35176b3409de6887c1cdd5c679939497b1b56f4554bBehdad Esfahbod 35214dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod enum base_position_t { 35314dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod BASE_FIRST, 35414dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod BASE_LAST 35514dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod } base_pos; 35614dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod 35714dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod switch ((hb_tag_t) buffer->props.script) 35814dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod { 35934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod case HB_SCRIPT_SINHALA: 36014dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod case HB_SCRIPT_KHMER: 36114dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod base_pos = BASE_FIRST; 36214dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod break; 36314dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod 36414dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod default: 36514dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod base_pos = BASE_LAST; 36614dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod break; 36714dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod } 36814dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod 36914dbdd9e39d3a869fd1521000c889c347433d22bBehdad Esfahbod if (base_pos == BASE_LAST) 3705d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 3715d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod /* -> starting from the end of the syllable, move backwards */ 3725d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod unsigned int i = end; 37392a1ad7bef9efb456ab87bd63818cfbed7da3f6fBehdad Esfahbod bool seen_below = false; 3745d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod do { 3755d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod i--; 3765d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod /* -> until a consonant is found */ 3775d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod if (is_consonant (info[i])) 3783c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod { 3795d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod /* -> that does not have a below-base or post-base form 3805d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod * (post-base forms have to follow below-base forms), */ 3815d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod if (info[i].indic_position() != POS_BELOW_C && 38292a1ad7bef9efb456ab87bd63818cfbed7da3f6fBehdad Esfahbod (info[i].indic_position() != POS_POST_C || seen_below)) 3835d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 3845d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = i; 3855d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod break; 3865d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 38792a1ad7bef9efb456ab87bd63818cfbed7da3f6fBehdad Esfahbod if (info[i].indic_position() == POS_BELOW_C) 38892a1ad7bef9efb456ab87bd63818cfbed7da3f6fBehdad Esfahbod seen_below = true; 3895d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 3905d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod /* -> or that is not a pre-base reordering Ra, 3915d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod * 39225e302da9a712e6f1d63b0d243a8df0d326ddba3Behdad Esfahbod * IMPLEMENTATION NOTES: 39325e302da9a712e6f1d63b0d243a8df0d326ddba3Behdad Esfahbod * 39425e302da9a712e6f1d63b0d243a8df0d326ddba3Behdad Esfahbod * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped 39525e302da9a712e6f1d63b0d243a8df0d326ddba3Behdad Esfahbod * by the logic above already. 3965d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod */ 3975d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 3985d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod /* -> or arrive at the first consonant. The consonant stopped at will 3995d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod * be the base. */ 4003c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod base = i; 4013c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod } 4025d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod else 403a9e45c32e4a0d6da33c52f8427aa694e57f52eb9Behdad Esfahbod { 40488f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod /* A ZWJ after a Halant stops the base search, and requests an explicit 40588f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod * half form. 40688f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod * A ZWJ before a Halant, requests a subjoined form instead, and hence 40788f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod * search continues. This is particularly important for Bengali 40888f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */ 40988f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod if (start < i && 41088f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod info[i].indic_category() == OT_ZWJ && 41188f413b56f2858d149e2fc067685aeecaea779caBehdad Esfahbod info[i - 1].indic_category() == OT_H) 4125d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod break; 413a9e45c32e4a0d6da33c52f8427aa694e57f52eb9Behdad Esfahbod } 4145d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } while (i > limit); 4155d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 4165d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod else 4175d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod { 4185d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */ 4195d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod 4205d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod if (!has_reph) 4215d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod base = limit; 42234c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 42334c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod /* Find the last base consonant that is not blocked by ZWJ. If there is 42471fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod * a ZWJ right before a base consonant, that would request a subjoined form. */ 42534c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod for (unsigned int i = limit; i < end; i++) 42634c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 42771fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod { 42871fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod if (limit < i && info[i - 1].indic_category() == OT_ZWJ) 42971fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod break; 43071fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod else 43171fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod base = i; 43271fd5e80ad06c8e85a1112cc89e129d6cd03f82cBehdad Esfahbod } 43334c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod 43434c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod /* Mark all subsequent consonants as below. */ 43534c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 43634c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C) 43734c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod info[i].indic_position() = POS_BELOW_C; 4385d32690a3428fa86eb26fe5fcec943a10aa95881Behdad Esfahbod } 439743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 440617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* -> If the syllable starts with Ra + Halant (in a script that has Reph) 441617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod * and has more than one consonant, Ra is excluded from candidates for 4422278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * base consonants. 4432278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * 4442278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ 4452278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod if (has_reph && base == start && start + 2 == limit) { 446617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod /* Have no other consonant, so Reph is not formed and Ra becomes base. */ 447617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod has_reph = false; 448617f4ac46f1084859d2034c08760e31e52d3bec3Behdad Esfahbod } 4495e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod } 4502278eefcdb3dd0d492b9d07176fbecc1f0516bb7Behdad Esfahbod 45134c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod if (base < end) 45234c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod info[base].indic_position() = POS_BASE_C; 4533d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 4543d25079f8d6be81b9b4b91d3a97016b8a572f571Behdad Esfahbod 455743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 2. Decompose and reorder Matras: 456743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 457743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Each matra and any syllable modifier sign in the cluster are moved to the 458743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * appropriate position relative to the consonant(s) in the cluster. The 459743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * shaping engine decomposes two- or three-part matras into their constituent 460743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * parts before any repositioning. Matra characters are classified by which 461743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * consonant in a conjunct they have affinity for and are reordered to the 462743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * following positions: 463743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 464743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o Before first half form in the syllable 465743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After subjoined consonants 466743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After post-form consonant 467743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * o After main consonant (for above marks) 468743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 469743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 470743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 471743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * The normalize() routine has already decomposed matras for us, so we don't 472743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * need to worry about that. 473743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 474743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 475743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 476743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* 3. Reorder marks to canonical order: 477743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 478743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * Adjacent nukta and halant or nukta and vedic sign are always repositioned 479743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * if necessary, so that the nukta is first. 480743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 481743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * IMPLEMENTATION NOTES: 482743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * 483743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * We don't need to do this: the normalize() routine already did this for us. 484743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod */ 485743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 486743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 48745d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod /* Reorder characters */ 48845d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 4893c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 490900cf3d449bf36d4f8b1474590cae925fef48fc8Behdad Esfahbod info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); 49155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 492075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 493075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].indic_position() = POS_BASE_C; 49445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 49555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod /* Mark final consonants. A final consonant is one appearing after a matra, 49655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod * like in Khmer. */ 49755f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 49855f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (info[i].indic_category() == OT_M) { 49955f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod for (unsigned int j = i + 1; j < end; j++) 50055f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod if (is_consonant (info[j])) { 50155f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod info[j].indic_position() = POS_FINAL_C; 50255f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 50355f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 50455f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod break; 50555f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod } 50655f70ebfb95083f515d9b0044a2a65ab11484bb5Behdad Esfahbod 507fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod /* Handle beginning Ra */ 5085e4e21fce4b548b0b8a5951bc8f35a9f27428192Behdad Esfahbod if (has_reph) 509dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() = POS_RA_TO_BECOME_REPH; 510fd06bf56110e73826b3d5c73ac964e2609450d46Behdad Esfahbod 511f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* For old-style Indic script tags, move the first post-base Halant after 512f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod * last consonant. */ 513a3e04bee2c2fa648759a87e460db6b4f1b685586Behdad Esfahbod if (IS_OLD_INDIC_TAG (map->get_chosen_script (0))) { 5143c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 515f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (info[i].indic_category() == OT_H) { 516f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod unsigned int j; 517f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod for (j = end - 1; j > i; j--) 518190eb31a16178269aecaf5d2ecc9012f956749f4Behdad Esfahbod if (is_consonant (info[j])) 519f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 520f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod if (j > i) { 521f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod /* Move Halant to after last consonant. */ 522f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod hb_glyph_info_t t = info[i]; 523f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); 524f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod info[j] = t; 525f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 526f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod break; 527f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 528f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod } 529f5bc2725cb892264ba223e0a49f7fd2c622a0730Behdad Esfahbod 53081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* Attach misc marks to previous char to move with them. */ 531ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 53281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod indic_position_t last_pos = POS_START; 53381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod for (unsigned int i = start; i < end; i++) 53481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 53581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) 53681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 53781202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() = last_pos; 53881202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (unlikely (indic_options ().uniscribe_bug_compatible && 53981202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_category() == OT_H && 54081202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[i].indic_position() == POS_PRE_M)) 54181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod { 54281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod /* 54381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * Uniscribe doesn't move the Halant with Left Matra. 54481202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod * TEST: U+092B,U+093F,U+094DE 54581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod */ 546ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod for (unsigned int j = i; j > start; j--) 5476a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[j - 1].indic_position() != POS_PRE_M) { 548ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod info[i].indic_position() = info[j - 1].indic_position(); 549ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod break; 550ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 55181202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 55281202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } else if (info[i].indic_position() != POS_SMVD) { 55381202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod last_pos = (indic_position_t) info[i].indic_position(); 554ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 55581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod } 556ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod } 55774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */ 55874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod { 55974ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod unsigned int last_halant = end; 56074ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 561deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i])) 56274ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod last_halant = i; 56374ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod else if (is_consonant (info[i])) { 56474ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod for (unsigned int j = last_halant; j < i; j++) 56581202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod if (info[j].indic_position() != POS_SMVD) 56681202bd860e4034c18d9f80c5a4f33d9f48463a3Behdad Esfahbod info[j].indic_position() = info[i].indic_position(); 56774ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 56874ccc6a1322f8c48c5f2a05f04821783c4b87a14Behdad Esfahbod } 56945d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 570a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod { 5717b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod /* Things are out-of-control for post base positions, they may shuffle 5727b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * around like crazy, so merge clusters. For pre-base stuff, we handle 5737b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod * cluster issues in final reordering. */ 5747b2a7dadd6c616bbfe1d8358700cab9cee88e584Behdad Esfahbod buffer->merge_clusters (base, end); 575a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Sit tight, rock 'n roll! */ 576d3637edb248162970e202e9d0671540274192844Behdad Esfahbod hb_bubble_sort (info + start, end - start, compare_indic_order); 577a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod /* Find base again */ 578a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = end; 5793c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < end; i++) 580a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod if (info[i].indic_position() == POS_BASE_C) { 581a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod base = i; 582a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod break; 583a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 584a391ff50b9a7b6ac3e58d199ea726b20ee6839bbBehdad Esfahbod } 58545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 586743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Setup masks now */ 587743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 588281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod { 589281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod hb_mask_t mask; 590281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod 591dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* Reph */ 592668c6046c1b3af3bd316bda0cc8636f2a5e8df42Behdad Esfahbod for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) 59370fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod info[i].mask |= basic_mask_array[RPHF]; 594dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 595281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Pre-base */ 59620b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = basic_mask_array[HALF]; 5973c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start; i < base; i++) 598281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 599281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Base */ 60020b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = 0; 601075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod if (base < end) 602075d671f1093d2e3c58f7f45568696030f1b3efdBehdad Esfahbod info[base].mask |= mask; 603281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod /* Post-base */ 60420b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod mask = basic_mask_array[BLWF] | basic_mask_array[ABVF] | basic_mask_array[PSTF]; 6053c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 606281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod info[i].mask |= mask; 607281683995a46ed37aeeb84061249758c59822457Behdad Esfahbod } 6089da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 60917d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod /* XXX This will not match for old-Indic spec since the Halant-Ra order is reversed already. */ 6105f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (basic_mask_array[PREF] && base + 2 < end) 61117d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod { 612771a8f50289e8fa458cfc3cd84f73a380ce98077Behdad Esfahbod /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ 6138e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i + 1 < end; i++) 614deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (is_halant_or_coeng (info[i]) && 6158e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[i + 1].indic_category() == OT_Ra) 6168e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 6170201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod info[i++].mask |= basic_mask_array[PREF]; 6180201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod info[i++].mask |= basic_mask_array[PREF]; 6190201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 6200201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod /* Mark the subsequent stuff with 'cfar'. Used in Khmer. 6210201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * Read the feature spec. 6220201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * This allows distinguishing the following cases with MS Khmer fonts: 6230201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+179A,U+17D2,U+1782 6240201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod * U+1784,U+17D2,U+1782,U+17D2,U+179A 6250201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod */ 6260201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod for (; i < end; i++) 6270201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod info[i].mask |= basic_mask_array[CFAR]; 6280201e0a4649ad5b607e50bcb9605e7a5b7143812Behdad Esfahbod 6298e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 6308e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 63117d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod } 63217d7de91d76406d3e92db37d9eef2fc615f06e68Behdad Esfahbod 6339da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod /* Apply ZWJ/ZWNJ effects */ 6343c2ea9481b1028e927e615a5434ebf8edcb5f891Behdad Esfahbod for (unsigned int i = start + 1; i < end; i++) 6359da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod if (is_joiner (info[i])) { 6369da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod bool non_joiner = info[i].indic_category() == OT_ZWNJ; 6376b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod unsigned int j = i; 6389da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod 6399da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod do { 6409da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod j--; 6416b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 64220b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWJ disables CJCT, however, it's mere presence is enough 64320b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod * to disable ligation. No explicit action needed. */ 64420b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod 64520b68e699f73e6ce046c0ec143d40b3d6d48e06bBehdad Esfahbod /* A ZWNJ disables HALF. */ 6466b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod if (non_joiner) 64770fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod info[j].mask &= ~basic_mask_array[HALF]; 6486b37bc80843e38ca7b62500f95fd70c08af68d62Behdad Esfahbod 6499da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } while (j > start && !is_consonant (info[j])); 6509da0487cd452d780673e24329ce03e174a4ef83bBehdad Esfahbod } 651743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 652743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 653743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 654743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 6559f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbodinitial_reordering_vowel_syllable (const hb_ot_map_t *map, 6569f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 65770fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod hb_mask_t *basic_mask_array, 658ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 659743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 660c5306b6861cfaa50af40e8ceb058791fa06d7981Behdad Esfahbod /* We made the vowels look like consonants. So let's call the consonant logic! */ 66170fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod initial_reordering_consonant_syllable (map, buffer, basic_mask_array, start, end); 662743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 663743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 664743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 6659f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbodinitial_reordering_standalone_cluster (const hb_ot_map_t *map, 6669f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer, 66770fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod hb_mask_t *basic_mask_array, 668ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 669743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 67018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. 67118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Only if not in compatibility mode that is... */ 67218c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 673a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 67418c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod { 67518c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod /* For dotted-circle, this is what Uniscribe does: 67618c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * If dotted-circle is the last glyph, it just does nothing. 67718c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod * Ie. It doesn't form Reph. */ 67818c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) 67918c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod return; 68018c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod } 68118c06e189bd078affbb84c3bb5bb80687a227c5eBehdad Esfahbod 68270fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod initial_reordering_consonant_syllable (map, buffer, basic_mask_array, start, end); 683743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 684743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 685743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 6869f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbodinitial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED, 6879f377ed3210fe7d9f15e0c4f82020556f9a8f6f0Behdad Esfahbod hb_buffer_t *buffer HB_UNUSED, 68870fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod hb_mask_t *basic_mask_array HB_UNUSED, 6893f18236a03880c0960f5990dc90685f6146951a6Behdad Esfahbod unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) 690743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 691743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod /* Nothing to do right now. If we ever switch to using the output 692743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod * buffer in the reordering process, we'd need to next_glyph() here. */ 693743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 694743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 695743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod#include "hb-ot-shape-complex-indic-machine.hh" 696743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 697743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 698743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodinitial_reordering (const hb_ot_map_t *map, 6993f18236a03880c0960f5990dc90685f6146951a6Behdad Esfahbod hb_face_t *face HB_UNUSED, 700743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod hb_buffer_t *buffer, 701743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod void *user_data HB_UNUSED) 702743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 70370fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod hb_mask_t basic_mask_array[ARRAY_LENGTH (indic_basic_features)] = {0}; 704b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod unsigned int num_masks = ARRAY_LENGTH (indic_basic_features); 705b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod for (unsigned int i = 0; i < num_masks; i++) 70670fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod basic_mask_array[i] = map->get_1_mask (indic_basic_features[i].tag); 707743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 70870fe77bb9a25922bd34f206826d8731d901fb451Behdad Esfahbod find_syllables (map, buffer, basic_mask_array); 709b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod} 710b9ddbd55930228422e82b34a141ad1b6093f5376Behdad Esfahbod 711743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbodstatic void 71246e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbodfinal_reordering_syllable (hb_buffer_t *buffer, 71346e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod hb_mask_t init_mask, hb_mask_t pref_mask, 714ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int start, unsigned int end) 715743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod{ 7164ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 7174ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 718e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod /* 4. Final reordering: 719e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 720e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * After the localized forms and basic shaping forms GSUB features have been 721e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * applied (see below), the shaping engine performs some final glyph 722e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * reordering before applying all the remaining font features to the entire 723e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * cluster. 7244ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 7254ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 7264ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* Find base again */ 7275f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod unsigned int base; 7285f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod for (base = start; base < end; base++) 7295f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (info[base].indic_position() >= POS_BASE_C) { 7305f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod if (start < base && info[base].indic_position() > POS_BASE_C) 7315f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod base--; 7325f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod break; 7335f0eaaad129ff04d56b8756bebf19fbc242718c9Behdad Esfahbod } 7344ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 7354705a7026900e51f6430f03a73c87f2df035df92Behdad Esfahbod 7364ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder matras: 737e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 738e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base matra character had been reordered before applying basic 739e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * features, the glyph can be moved closer to the main consonant based on 740e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * whether half-forms had been formed. Actual position for the matra is 741e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * defined as “after last standalone halant glyph, after initial matra 742e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * position and before the main consonant”. If ZWJ or ZWNJ follow this 743e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * halant, position is moved after it. 7444ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod */ 7454ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 74665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */ 7479d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 74865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we lost track of base, alas, position before last thingy. */ 74965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod unsigned int new_pos = base == end ? base - 2 : base - 1; 75065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 75165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* Malayalam does not have "half" forms or explicit virama forms. 75265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * The glyphs formed by 'half' are Chillus. We want to position 75365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * matra after them all. 75465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod */ 75565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (buffer->props.script != HB_SCRIPT_MALAYALAM) 756e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod { 75765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod while (new_pos > start && 75865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) 75965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos--; 76065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod 76165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* If we found no Halant we are done. 76265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * Otherwise only proceed if the Halant does 76365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod * not belong to the Matra itself! */ 76465c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (is_halant_or_coeng (info[new_pos]) && 76565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod info[new_pos].indic_position() != POS_PRE_M) 76665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 76765c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 76865c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (new_pos + 1 < end && is_joiner (info[new_pos + 1])) 76965c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos++; 77065c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 77165c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod else 77265c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod new_pos = start; /* No move. */ 77365c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod } 7749d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod 77565c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod if (start < new_pos) 77665c43accdc4d2082282d5cedba8514b8df0c18a2Behdad Esfahbod { 7779d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* Now go see if there's actually any matras... */ 778921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod for (unsigned int i = new_pos; i > start; i--) 7796a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[i - 1].indic_position () == POS_PRE_M) 7809d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod { 7811a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod unsigned int old_pos = i - 1; 7821a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 7831a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0])); 7841a1dbe9a2787f226f3e43063da8eb6633438b0a0Behdad Esfahbod info[new_pos] = tmp; 785921ce5b17daf06af8e17989a3e335b9f5df20483Behdad Esfahbod new_pos--; 7869d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 7872cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (new_pos, MIN (end, base + 1)); 788abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } else { 789e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod for (unsigned int i = start; i < base; i++) 790abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod if (info[i].indic_position () == POS_PRE_M) { 7912cc933aff97916e5d0fe42883f40f0879f848e25Behdad Esfahbod buffer->merge_clusters (i, MIN (end, base + 1)); 792abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod break; 793abb3239ef92cc5dccb4638806d7ae9868b9ac9b3Behdad Esfahbod } 7949d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod } 7954ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod } 7964ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 7974ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod 7984ac9e98d9d2ea973dd612dc4063cf78496c643a0Behdad Esfahbod /* o Reorder reph: 799e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 800e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Reph’s original position is always at the beginning of the syllable, 801e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * (i.e. it is not reordered at the character reordering stage). However, 802e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * it will be reordered according to the basic-forms shaping results. 803e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * Possible positions for reph, depending on the script, are; after main, 804e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * before post-base consonant forms, and after post-base consonant forms. 805dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 806dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 807dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* If there's anything after the Ra that has the REPH pos, it ought to be halant. 808dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Which means that the font has failed to ligate the Reph. In which case, we 809dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * shouldn't move. */ 810dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod if (start + 1 < end && 811dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start].indic_position() == POS_RA_TO_BECOME_REPH && 812dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) 813dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod { 81402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod unsigned int new_reph_pos; 81502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 81602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod enum reph_position_t { 817f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod REPH_AFTER_MAIN, 818f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod REPH_BEFORE_SUBSCRIPT, 819f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod REPH_AFTER_SUBSCRIPT, 820f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod REPH_BEFORE_POSTSCRIPT, 8219fc7a11469113d31d8095757c4fc038c3427d44aBehdad Esfahbod REPH_AFTER_POSTSCRIPT 822f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod } reph_pos; 823f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod 824f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod /* XXX Figure out old behavior too */ 8257f852b644b8143492a02edfc853114aaa23446bdBehdad Esfahbod switch ((hb_tag_t) buffer->props.script) 826f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod { 827f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_MALAYALAM: 828f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_ORIYA: 82934c215036f5fcdc7599b1ab0591b56dbb3811902Behdad Esfahbod case HB_SCRIPT_SINHALA: 830f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod reph_pos = REPH_AFTER_MAIN; 831f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod break; 832f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod 833f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_GURMUKHI: 834f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod reph_pos = REPH_BEFORE_SUBSCRIPT; 835f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod break; 836f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod 837f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_BENGALI: 838f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod reph_pos = REPH_AFTER_SUBSCRIPT; 839f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod break; 840f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod 841f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod default: 842f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_DEVANAGARI: 843f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_GUJARATI: 844f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod reph_pos = REPH_BEFORE_POSTSCRIPT; 845f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod break; 846f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod 847f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_KANNADA: 848f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_TAMIL: 849f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod case HB_SCRIPT_TELUGU: 850f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod reph_pos = REPH_AFTER_POSTSCRIPT; 851f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod break; 852f89367251109af235f4f0446c13c261a5a4a6f72Behdad Esfahbod } 85302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 854dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* 1. If reph should be positioned after post-base consonant forms, 855dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to step 5. 85602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 8579d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (reph_pos == REPH_AFTER_POSTSCRIPT) 85802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 8599d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_step_5; 86002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 86102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 86202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 2. If the reph repositioning class is not after post-base: target 863dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is after the first explicit halant glyph between the 864dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-reph consonant and last main consonant. If ZWJ or ZWNJ 865dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * are following this halant, position is moved after it. If such 866dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * position is found, this is the target position. Otherwise, 867dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * proceed to the next step. 868dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * 869dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * Note: in old-implementation fonts, where classifications were 870dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * fixed in shaping engine, there was no case where reph position 871dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * will be found on this step. 87202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 87302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 87402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = start + 1; 875deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 87602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 87702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 878deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 87902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 88002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 88102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos++; 88202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 88302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 88402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 88502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 88602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 3. If reph should be repositioned after the main consonant: find the 887dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first consonant not ligated with main, or find the first 888dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant that is not a potential pre-base reordering Ra. 88902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 8909d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (reph_pos == REPH_AFTER_MAIN) 89102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 892b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos = base; 893b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod /* XXX Skip potential pre-base reordering Ra. */ 89434ae336f3fae93ef9372881d545c817bce383041Behdad Esfahbod while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN) 895b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod new_reph_pos++; 896b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod if (new_reph_pos < end) 897b504e060f008e95b1ba36c06600c9fea4f5d4808Behdad Esfahbod goto reph_move; 89802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 89902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 90002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 4. If reph should be positioned before post-base consonant, find 901dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first post-base classified consonant not ligated with main. If no 902dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * consonant is found, the target position should be before the 903dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * first matra, syllable modifier sign or vedic sign. 90402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 9059d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod /* This is our take on what step 4 is trying to say (and failing, BADLY). */ 9069d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (reph_pos == REPH_AFTER_SUBSCRIPT) 90702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 9089d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos = base; 9099d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod while (new_reph_pos < end && 910be8b9f5f715f6fb36b98bd33c3303f79cc068f8aBehdad Esfahbod !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD)))) 9119d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod new_reph_pos++; 9129d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod if (new_reph_pos < end) 9139d0d319a4a7e85d922e58fade0f40caae1c9f109Behdad Esfahbod goto reph_move; 91402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 91502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 91602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 5. If no consonant is found in steps 3 or 4, move reph to a position 917dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * immediately before the first post-base matra, syllable modifier 918dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * sign or vedic sign that has a reordering class after the intended 919dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * reph position. For example, if the reordering position for reph 920dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * is post-main, it will skip above-base matras that also have a 921dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod * post-main position. 922dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod */ 92302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_step_5: 92402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 925d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* Copied from step 2. */ 926d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos = start + 1; 927d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) 928d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 929d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod 930d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { 931d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ 932d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) 933d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod new_reph_pos++; 934d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod goto reph_move; 935d0e68dbd0b9fc9a42c4280d01c8ffd9c5015d550Behdad Esfahbod } 93602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 937dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 93802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* 6. Otherwise, reorder reph to the end of the syllable. 93902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod */ 94002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 94102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos = end - 1; 94202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) 94302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 94402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod 945892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod /* 946892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * If the Reph is to be ending up after a Matra,Halant sequence, 947892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * position it before that Halant so it can interact with the Matra. 948892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * However, if it's a plain Consonant,Halant we shouldn't do that. 949892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * Uniscribe doesn't do this. 950892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod * TEST: U+0930,U+094D,U+0915,U+094B,U+094D 951892eb7878238d810a2a70f9dadbf958207bfeaa1Behdad Esfahbod */ 952a2b471df821b32625d127f83b2f90e6d6a967e7eBehdad Esfahbod if (!indic_options ().uniscribe_bug_compatible && 953deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod unlikely (is_halant_or_coeng (info[new_reph_pos]))) { 95402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod for (unsigned int i = base + 1; i < new_reph_pos; i++) 95502b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod if (info[i].indic_category() == OT_M) { 95602b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Ok, got it. */ 95702b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod new_reph_pos--; 95802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 95902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 96002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod goto reph_move; 9618df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod } 9628df5636968389ac7bf8620ccd091fd4872b0bbeeBehdad Esfahbod 96302b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod reph_move: 96402b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod { 965e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod /* Yay, one big cluster! Merge before moving. */ 966e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 967e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod 96802b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod /* Move */ 96902b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod hb_glyph_info_t reph = info[start]; 97002b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); 97102b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod info[new_reph_pos] = reph; 97202b2922fbf098c8282eb23dc2c54d5829cf67024Behdad Esfahbod } 973dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod } 974dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 975dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod 976dbb105883c6e9b83e78dc8b10766cd56b98cd7e1Behdad Esfahbod /* o Reorder pre-base reordering consonants: 977e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * 978e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * If a pre-base reordering consonant is found, reorder it according to 979e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod * the following rules: 980e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod */ 981e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 98246e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod if (pref_mask && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ 98346e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod { 9848e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod for (unsigned int i = base + 1; i < end; i++) 9858e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if ((info[i].mask & pref_mask) != 0) 98678818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod { 9878e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 1. Only reorder a glyph produced by substitution during application 9888e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * of the <pref> feature. (Note that a font may shape a Ra consonant with 9898e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * the feature generally but block it in certain contexts.) 9908e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 9918e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (i + 1 == end || (info[i + 1].mask & pref_mask) == 0) 9928e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 9938e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* 9948e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 2. Try to find a target position the same way as for pre-base matra. 9958e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * If it is found, reorder pre-base consonant glyph. 9968e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 9978e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * 3. If position is not found, reorder immediately before main 9988e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod * consonant. 9998e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod */ 10008e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10018e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int new_pos = base; 10020afb84c12567ac35adac657bf8be29999b8c5a50Behdad Esfahbod while (new_pos > start && 10030afb84c12567ac35adac657bf8be29999b8c5a50Behdad Esfahbod !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS))) 10048e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos--; 10058e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 1006d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod /* In Khmer coeng model, a V,Ra can go *after* matras. If it goes after a 1007d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod * split matra, it should be reordered to *before* the left part of such matra. */ 1008d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod if (new_pos > start && info[new_pos - 1].indic_category() == OT_M) 1009d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 1010d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod unsigned int old_pos = i; 1011d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod for (unsigned int i = base + 1; i < old_pos; i++) 1012d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod if (info[i].indic_category() == OT_M) 1013d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod { 1014d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod new_pos--; 1015d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod break; 1016d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1017d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod } 1018d90b8e841e0068a601c96ab184d18b0f48eec9d1Behdad Esfahbod 1019deb521dee4fdca8c2124cfb39a205e6269d4a70dBehdad Esfahbod if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) 10208e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ 10218e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod if (new_pos < end && is_joiner (info[new_pos])) 10228e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod new_pos++; 10238e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10248e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod { 10258e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod unsigned int old_pos = i; 1026e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (new_pos, old_pos + 1); 10278e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod hb_glyph_info_t tmp = info[old_pos]; 10288e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0])); 10298e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod info[new_pos] = tmp; 10308e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 10318e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod } 10328e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod 10338e7b5882fb4c1921c9d030d354a9b998115cdb8cBehdad Esfahbod break; 103478818124b17691ec2c647142fdb9ae743aa03deeBehdad Esfahbod } 103546e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod } 1036eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1037eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1038a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod /* Apply 'init' to the Left Matra if it's a word start. */ 10396a091df9b403b147ef78f3974610dedf4ce1e08aBehdad Esfahbod if (info[start].indic_position () == POS_PRE_M && 1040a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod (!start || 1041eace47b173807d94b29a6490d0bc3c9f8f6168d1Behdad Esfahbod !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & 10422c372b80f6befad69e216e3f218b38640b8cc044Behdad Esfahbod FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))) 104346e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod info[start].mask |= init_mask; 1044a913b024d84973556094fd64ce5f0b7106fcc3b5Behdad Esfahbod 1045eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 10468ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod /* 10478ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod * Finish off the clusters and go home! 10488ed248de77e5d2ed978e55c0ce1a11727bc9e34cBehdad Esfahbod */ 1049decf6ffca475fe01ff3151b7641f629f031137d2Behdad Esfahbod if (indic_options ().uniscribe_bug_compatible) 1050ebe29733d44fe0fa9fb30f946ab0dd7a40336a24Behdad Esfahbod { 105130c3d5e9fc61b49c2c6ad4e744300edd6f3e0261Behdad Esfahbod /* Uniscribe merges the entire cluster. 105221d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This means, half forms are submerged into the main consonants cluster. 105321d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * This is unnecessary, and makes cursor positioning harder, but that's what 105421d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod * Uniscribe does. */ 1055e6b01a878cd2e63cb675e7e0c6ac4d83a8c10f37Behdad Esfahbod buffer->merge_clusters (start, end); 105621d2803133c2c424ed37a9f3d17c7fc4963e5a60Behdad Esfahbod } 1057ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod} 1058e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1059e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1060ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodstatic void 1061ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbodfinal_reordering (const hb_ot_map_t *map, 10623f18236a03880c0960f5990dc90685f6146951a6Behdad Esfahbod hb_face_t *face HB_UNUSED, 1063ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_buffer_t *buffer, 1064ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod void *user_data HB_UNUSED) 1065ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod{ 1066ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int count = buffer->len; 1067ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod if (!count) return; 1068ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod 106946e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod hb_mask_t init_mask = map->get_1_mask (HB_TAG('i','n','i','t')); 107046e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod hb_mask_t pref_mask = map->get_1_mask (HB_TAG('p','r','e','f')); 1071eed903b1644e087178438959664a6a57bebc398bBehdad Esfahbod 1072ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod hb_glyph_info_t *info = buffer->info; 1073ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod unsigned int last = 0; 1074cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod unsigned int last_syllable = info[0].syllable(); 1075ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod for (unsigned int i = 1; i < count; i++) 1076cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod if (last_syllable != info[i].syllable()) { 107746e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod final_reordering_syllable (buffer, init_mask, pref_mask, last, i); 1078ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod last = i; 1079cee7187447b76b22e1bb6136d137b35ac49c3a5dBehdad Esfahbod last_syllable = info[last].syllable(); 1080ef24cc8c8e2478a6352c340f4611a617646de4ccBehdad Esfahbod } 108146e645ec4b59f0a278347be11f40c7df700d5bb6Behdad Esfahbod final_reordering_syllable (buffer, init_mask, pref_mask, last, count); 1082e7be05702447ae270d797398132c1930cd3a9b86Behdad Esfahbod 1083743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); 1084743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); 1085743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod} 1086743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1087743807a3ce1b2229e5307a8aea074a7544623d8dBehdad Esfahbod 1088693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = 1089693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 1090693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "indic", 1091693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_indic, 1092693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod override_features_indic, 1093693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod NULL, /* normalization_preference */ 1094693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_indic, 10951e7d860613032e40a3f90e2caa2ee5ac44ab8c8cBehdad Esfahbod false, /* zero_width_attached_marks */ 1096693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 1097