13eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/* 2e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod * Copyright © 2010,2012 Google, Inc. 33eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * 43eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * This is part of HarfBuzz, a text shaping library. 53eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * 63eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Permission is hereby granted, without written agreement and without 73eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this 83eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * software and its documentation for any purpose, provided that the 93eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * above copyright notice and the following two paragraphs appear in 103eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * all copies of this software. 113eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * 123eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 133eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 143eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 153eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 163eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * DAMAGE. 173eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * 183eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 193eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 203eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 213eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 223eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 233eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * 243eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Google Author(s): Behdad Esfahbod 253eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod */ 263eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 2713403bc67a01e0d4908fb964093fd02ddd11c580Behdad Esfahbod#include "hb-ot-shape-complex-private.hh" 28d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod#include "hb-ot-shape-private.hh" 293eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 303a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod 313a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod/* buffer var allocations */ 32cd0c6e148f6d078b364370cb2f808b793b921be2Behdad Esfahbod#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */ 333a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod 343a852ae7fe6edfaadd75625d27515a3689503395Behdad Esfahbod 353eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/* 363eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Bits used in the joining tables 373eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod */ 383eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbodenum { 393eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod JOINING_TYPE_U = 0, 40c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_TYPE_L = 1, 41c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_TYPE_R = 2, 42c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_TYPE_D = 3, 433eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod JOINING_TYPE_C = JOINING_TYPE_D, 44c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_GROUP_ALAPH = 4, 45c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_GROUP_DALATH_RISH = 5, 46c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod NUM_STATE_MACHINE_COLS = 6, 473eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 48c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_TYPE_T = 7, 49c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */ 503eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod}; 513eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 523eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/* 533eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod * Joining types: 543eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod */ 553eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 56c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include "hb-ot-shape-complex-arabic-table.hh" 573eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 5899b74760a4cddc798ab44b5ca897486bbb9c76d6Behdad Esfahbodstatic unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat) 593eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{ 60b900fa2c8cc088dbcbdbf90bfdf8764f9ee1c96aBehdad Esfahbod unsigned int j_type = joining_type(u); 61b900fa2c8cc088dbcbdbf90bfdf8764f9ee1c96aBehdad Esfahbod if (likely (j_type != JOINING_TYPE_X)) 62b900fa2c8cc088dbcbdbf90bfdf8764f9ee1c96aBehdad Esfahbod return j_type; 633eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 645d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod return (FLAG(gen_cat) & 655d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | 665d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | 675d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT)) 685d4d7384efa97a30893ad28b9ad9a994722de12cBehdad Esfahbod ) ? JOINING_TYPE_T : JOINING_TYPE_U; 693eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod} 703eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 71615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3') 72615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod 73e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstatic const hb_tag_t arabic_features[] = 743eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{ 753eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod HB_TAG('i','s','o','l'), 76615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod HB_TAG('f','i','n','a'), 773eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod HB_TAG('f','i','n','2'), 783eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod HB_TAG('f','i','n','3'), 79615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod HB_TAG('m','e','d','i'), 80615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod HB_TAG('m','e','d','2'), 81615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod HB_TAG('i','n','i','t'), 823eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod HB_TAG_NONE 833eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod}; 843eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 853eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 863eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod/* Same order as the feature array */ 873eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbodenum { 883eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod ISOL, 89615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod FINA, 903eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod FIN2, 913eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod FIN3, 92615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod MEDI, 93615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod MED2, 94615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod INIT, 953eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 963eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod NONE, 973eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 98e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod ARABIC_NUM_FEATURES = NONE 993eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod}; 1003eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1013eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbodstatic const struct arabic_state_table_entry { 1023eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod uint8_t prev_action; 1033eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod uint8_t curr_action; 10431f18abecb149f8888a72510f2660328dd6de16dBehdad Esfahbod uint16_t next_state; 1053eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod} arabic_state_table[][NUM_STATE_MACHINE_COLS] = 1063eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{ 107c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod /* jt_U, jt_L, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */ 1083eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1093eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod /* State 0: prev was U, not willing to join. */ 110c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, }, 1113eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1123eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod /* State 1: prev was R or ISOL/ALAPH, not willing to join. */ 113c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, }, 1143eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 115c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod /* State 2: prev was D/L in ISOL form, willing to join. */ 116c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, }, 1173eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 118c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod /* State 3: prev was D in FINA form, willing to join. */ 119c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, }, 1203eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1213eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod /* State 4: prev was FINA ALAPH, not willing to join. */ 122c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, }, 1233eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1243eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */ 125c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, }, 1263eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1273eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod /* State 6: prev was DALATH/RISH, not willing to join. */ 128c2a1cdc4c4cc51f4680ebc4ec2c462cb660f9492Behdad Esfahbod { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, } 1293eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod}; 1303eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 1313eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 132fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodstatic void 133c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodnuke_joiners (const hb_ot_shape_plan_t *plan, 134c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod hb_font_t *font, 135c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod hb_buffer_t *buffer); 136c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod 137c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodstatic void 138fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodarabic_fallback_shape (const hb_ot_shape_plan_t *plan, 139fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod hb_font_t *font, 140fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod hb_buffer_t *buffer); 14149baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod 142693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 14316c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbodcollect_features_arabic (hb_ot_shape_planner_t *plan) 14449baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod{ 14516c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod hb_ot_map_builder_t *map = &plan->map; 14616c6a27b4bffc19026944c7bea9cf0a3a8ff1d8fBehdad Esfahbod 147615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod /* We apply features according to the Arabic spec, with pauses 148615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * in between most. 149b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod * 150615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * The pause between init/medi/... and rlig is required. See eg: 151b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod * https://bugzilla.mozilla.org/show_bug.cgi?id=644184 15271b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod * 153615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * The pauses between init/medi/... themselves are not necessarily 154615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * needed as only one of those features is applied to any character. 155615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * The only difference it makes is when fonts have contextual 156615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * substitutions. We now follow the order of the spec, which makes 157615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * for better experience if that's what Uniscribe is doing. 158615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * 159615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * At least for Arabic, looks like Uniscribe has a pause between 160615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't 161615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * work. However, testing shows that rlig and calt are applied 162615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * together for Mongolian in Uniscribe. As such, we only add a 163615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod * pause for Arabic, not other scripts. 164b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod */ 165b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod 166c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod map->add_gsub_pause (nuke_joiners); 167c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod 168e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('c','c','m','p')); 169e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('l','o','c','l')); 170f6fd3780e12b23ff7ed3743497c8996e71dcb064Behdad Esfahbod 1713e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 172a71b9c8579d73aea4549f12524bbc2e89f43b5c5Behdad Esfahbod 173e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) 174615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod { 175615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]); 176615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE); 177615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod map->add_gsub_pause (NULL); 178615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod } 179b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod 180ec5448667b30ad662401c2b4f5fc0da524c013fdBehdad Esfahbod map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); 181615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod if (plan->props.script == HB_SCRIPT_ARABIC) 182615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod map->add_gsub_pause (arabic_fallback_shape); 183b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod 184e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('c','a','l','t')); 1853e38c0f2886c38d2f0a9d80a97a36edf2479d2c7Behdad Esfahbod map->add_gsub_pause (NULL); 186b70c96dbe41d6512b80fe3d966a1942e1ef64a4bBehdad Esfahbod 18782f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod /* The spec includes 'cswh'. Earlier versions of Windows 18882f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * used to enable this by default, but testing suggests 18982f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * that Windows 8 and later do not enable it by default, 19082f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * and spec now says 'Off by default'. 19182f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * We disabled this in ae23c24c32. 19282f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * Note that IranNastaliq uses this feature extensively 19382f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * to fixup broken glyph sequences. Oh well... 19482f4d9d53f348f41b14b877c1ac77c0372c49caaBehdad Esfahbod * Test case: U+0643,U+0640,U+0631. */ 195e3b42f1af409c073b819bfc696024ccb1f1da63fBehdad Esfahbod //map->add_global_bool_feature (HB_TAG('c','s','w','h')); 196e7ffcfafb1108801ac504f18f820e497226bf07fBehdad Esfahbod map->add_global_bool_feature (HB_TAG('m','s','e','t')); 19749baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod} 19849baa1f69efb0e3c62e45bd59dd88459a84bf390Behdad Esfahbod 199fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod#include "hb-ot-shape-complex-arabic-fallback.hh" 200fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod 201e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstruct arabic_shape_plan_t 202e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod{ 203e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod ASSERT_POD (); 204e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod 2052f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod /* The "+ 1" in the next array is to accommodate for the "NONE" command, 2062f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod * which is not an OpenType feature, but this simplifies the code by not 2072f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod * having to do a "if (... < NONE) ..." and just rely on the fact that 2082f1747ed7d28148807ad07eb8e22db3ab5c54966Behdad Esfahbod * mask_array[NONE] == 0. */ 209bd08d5d126aa878d1dbf7bfd4b1a764c170cd9adBehdad Esfahbod hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1]; 210fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod 211fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod bool do_fallback; 212fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_fallback_plan_t *fallback_plan; 213e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod}; 214e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod 215e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstatic void * 216e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahboddata_create_arabic (const hb_ot_shape_plan_t *plan) 217e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod{ 218e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t)); 219e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod if (unlikely (!arabic_plan)) 220e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod return NULL; 221e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod 222fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC; 223e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { 224e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]); 225615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod arabic_plan->do_fallback = arabic_plan->do_fallback && 226615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod !FEATURE_IS_SYRIAC (arabic_features[i]) && 227615d00ea252739da57edbd980ff27e573f88ee7eBehdad Esfahbod plan->map.needs_fallback (arabic_features[i]); 228e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod } 229e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod 230e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod return arabic_plan; 231e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod} 232e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod 233e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbodstatic void 234e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahboddata_destroy_arabic (void *data) 235e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod{ 236fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data; 237939c010211b063f78874a3b72b032c1ed9a13b87Behdad Esfahbod 238fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_fallback_plan_destroy (arabic_plan->fallback_plan); 2392fcbbdb41a322f54b61d9ce983ab54434504c5edBehdad Esfahbod 240fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod free (data); 241b7d04eb606800100faa11100d2adf559e297a4eeBehdad Esfahbod} 242b7d04eb606800100faa11100d2adf559e297a4eeBehdad Esfahbod 243693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodstatic void 2449f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbodarabic_joining (hb_buffer_t *buffer) 2453eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod{ 24676f76812ac7cca8ac6935952a2360d5e151480faBehdad Esfahbod unsigned int count = buffer->len; 2477cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 248bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod unsigned int prev = (unsigned int) -1, state = 0; 2493eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 250bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod /* Check pre-context */ 2510c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod if (!(buffer->flags & HB_BUFFER_FLAG_BOT)) 2520c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod for (unsigned int i = 0; i < buffer->context_len[0]; i++) 2530c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod { 2540c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i])); 255bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod 2560c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod if (unlikely (this_type == JOINING_TYPE_T)) 2570c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod continue; 258bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod 2590c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; 2600c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod state = entry->next_state; 2610c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod break; 2620c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod } 263bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod 264758f68b860b44b5a04eb3dde5cb40b1b04cf634aBehdad Esfahbod for (unsigned int i = 0; i < count; i++) 265758f68b860b44b5a04eb3dde5cb40b1b04cf634aBehdad Esfahbod { 2667cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i])); 2673eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 268aefdb64689aab19df76590a36c4a04052a8bffdbBehdad Esfahbod if (unlikely (this_type == JOINING_TYPE_T)) { 2697cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod info[i].arabic_shaping_action() = NONE; 2703eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod continue; 271aefdb64689aab19df76590a36c4a04052a8bffdbBehdad Esfahbod } 2723eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 273758f68b860b44b5a04eb3dde5cb40b1b04cf634aBehdad Esfahbod const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; 2743eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 275bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod if (entry->prev_action != NONE && prev != (unsigned int) -1) 2767cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod info[prev].arabic_shaping_action() = entry->prev_action; 2773eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 2787cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod info[i].arabic_shaping_action() = entry->curr_action; 2793eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 2803eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod prev = i; 2813eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod state = entry->next_state; 2823eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod } 2833eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 2840c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod if (!(buffer->flags & HB_BUFFER_FLAG_EOT)) 2850c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod for (unsigned int i = 0; i < buffer->context_len[1]; i++) 2860c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod { 2875669a6cf418f3a8b9281c36e9d662d843be80433Behdad Esfahbod unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i])); 288bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod 2890c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod if (unlikely (this_type == JOINING_TYPE_T)) 2900c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod continue; 291bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod 2920c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; 2930c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod if (entry->prev_action != NONE && prev != (unsigned int) -1) 2947cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod info[prev].arabic_shaping_action() = entry->prev_action; 2950c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod break; 2960c7df2222862122ebbdc8665a21d6771ef5e0252Behdad Esfahbod } 297164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod} 298bdc2fc8294da7f374701aafe9f5a82d60633946fBehdad Esfahbod 299164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbodstatic void 300164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbodmongolian_variation_selectors (hb_buffer_t *buffer) 301164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod{ 302164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */ 303164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod unsigned int count = buffer->len; 304164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 305164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod for (unsigned int i = 1; i < count; i++) 306164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du))) 307164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action(); 3089f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod} 3099f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod 3109f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbodstatic void 311fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodsetup_masks_arabic (const hb_ot_shape_plan_t *plan, 312fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod hb_buffer_t *buffer, 3130beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod hb_font_t *font HB_UNUSED) 3149f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod{ 315164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action); 316164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod 3179f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; 3189f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod 319fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_joining (buffer); 320164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod if (plan->props.script == HB_SCRIPT_MONGOLIAN) 321164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod mongolian_variation_selectors (buffer); 322164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod 323fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod unsigned int count = buffer->len; 3247cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 325fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 3267cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()]; 327164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod 328164c13d73f67fdddba28e6409d76b4903e8ffab3Behdad Esfahbod HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); 3299f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod} 330b65c06025d2b54a44f716e030d4b10072c65bea8Behdad Esfahbod 331fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod 3329f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbodstatic void 333c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodnuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED, 334c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod hb_font_t *font HB_UNUSED, 335c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod hb_buffer_t *buffer) 336c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod{ 337c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod unsigned int count = buffer->len; 3387cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod hb_glyph_info_t *info = buffer->info; 339c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 3407cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod if (_hb_glyph_info_is_zwj (&info[i])) 3417cd33f230441093dbfb1fec48f8c580ee8d9ef71Behdad Esfahbod _hb_glyph_info_flip_joiners (&info[i]); 342c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod} 343c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbod 344c52ddab72e025d1bee8274c8f3416208b12f68f1Behdad Esfahbodstatic void 345fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodarabic_fallback_shape (const hb_ot_shape_plan_t *plan, 346fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod hb_font_t *font, 347fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod hb_buffer_t *buffer) 3489f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod{ 3499f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; 3509f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod 351fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod if (!arabic_plan->do_fallback) 352fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod return; 353fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod 354fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbodretry: 355fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan); 356fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod if (unlikely (!fallback_plan)) 3579f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod { 358fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod /* This sucks. We need a font to build the fallback plan... */ 359fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod fallback_plan = arabic_fallback_plan_create (plan, font); 360fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) { 361fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_fallback_plan_destroy (fallback_plan); 362fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod goto retry; 363fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod } 3649f9f04c2229227bb0712166e824157bbbf5cef80Behdad Esfahbod } 365fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod 366fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod arabic_fallback_plan_shape (fallback_plan, font, buffer); 3673eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod} 3683eb936f1539475098f39be78654b9c39b86f0799Behdad Esfahbod 369fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod 370693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbodconst hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = 371693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod{ 372693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod "arabic", 373693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod collect_features_arabic, 374693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod NULL, /* override_features */ 375e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod data_create_arabic, 376e9f28a38f54b98fa59f9159ccaaa3be6027e1378Behdad Esfahbod data_destroy_arabic, 377fabd3113a98c5f4114f48920fa7ea38bd65a8d32Behdad Esfahbod NULL, /* preprocess_text_arabic */ 3783d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, 3790736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod NULL, /* decompose */ 3800736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod NULL, /* compose */ 381693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod setup_masks_arabic, 38271b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, 383865745b5b87236651f5663cae3461db9cb505eedBehdad Esfahbod true, /* fallback_position */ 384693918ef8541014a5ef7dfb91c6ea0ae36d9c368Behdad Esfahbod}; 385