| File: | jdk/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh |
| Warning: | line 329, column 3 Argument to free() is the address of the global variable '_hb_NullPool', which is not memory allocated by malloc() |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright © 2010,2012 Google, Inc. | |||
| 3 | * | |||
| 4 | * This is part of HarfBuzz, a text shaping library. | |||
| 5 | * | |||
| 6 | * Permission is hereby granted, without written agreement and without | |||
| 7 | * license or royalty fees, to use, copy, modify, and distribute this | |||
| 8 | * software and its documentation for any purpose, provided that the | |||
| 9 | * above copyright notice and the following two paragraphs appear in | |||
| 10 | * all copies of this software. | |||
| 11 | * | |||
| 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |||
| 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |||
| 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |||
| 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |||
| 16 | * DAMAGE. | |||
| 17 | * | |||
| 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |||
| 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |||
| 20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |||
| 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |||
| 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |||
| 23 | * | |||
| 24 | * Google Author(s): Behdad Esfahbod | |||
| 25 | */ | |||
| 26 | ||||
| 27 | #include "hb.hh" | |||
| 28 | ||||
| 29 | #ifndef HB_NO_OT_SHAPE | |||
| 30 | ||||
| 31 | #include "hb-ot-shape-complex-arabic.hh" | |||
| 32 | #include "hb-ot-shape.hh" | |||
| 33 | ||||
| 34 | ||||
| 35 | /* buffer var allocations */ | |||
| 36 | #define arabic_shaping_action()var2.u8[3] complex_var_u8_auxiliary()var2.u8[3] /* arabic shaping action */ | |||
| 37 | ||||
| 38 | #define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCHHB_BUFFER_SCRATCH_FLAG_COMPLEX0 HB_BUFFER_SCRATCH_FLAG_COMPLEX0 | |||
| 39 | ||||
| 40 | /* See: | |||
| 41 | * https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */ | |||
| 42 | #define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat)(((unsigned)(gen_cat) < 32 ? (((uint32_t) 1U) << (unsigned )(gen_cat)) : 0) & ((static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL ))))) \ | |||
| 43 | (FLAG_UNSAFE (gen_cat)((unsigned)(gen_cat) < 32 ? (((uint32_t) 1U) << (unsigned )(gen_cat)) : 0) & \ | |||
| 44 | (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED ))) | \ | |||
| 45 | FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE ))) | \ | |||
| 46 | /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \ | |||
| 47 | FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER ))) | \ | |||
| 48 | FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER ))) | \ | |||
| 49 | /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \ | |||
| 50 | /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \ | |||
| 51 | FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK ))) | \ | |||
| 52 | FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ))) | \ | |||
| 53 | FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ))) | \ | |||
| 54 | FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER ))) | \ | |||
| 55 | FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER ))) | \ | |||
| 56 | FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER ))) | \ | |||
| 57 | FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL ))) | \ | |||
| 58 | FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL ))) | \ | |||
| 59 | FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL ))) | \ | |||
| 60 | FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL ))))) | |||
| 61 | ||||
| 62 | ||||
| 63 | /* | |||
| 64 | * Joining types: | |||
| 65 | */ | |||
| 66 | ||||
| 67 | /* | |||
| 68 | * Bits used in the joining tables | |||
| 69 | */ | |||
| 70 | enum hb_arabic_joining_type_t { | |||
| 71 | JOINING_TYPE_U = 0, | |||
| 72 | JOINING_TYPE_L = 1, | |||
| 73 | JOINING_TYPE_R = 2, | |||
| 74 | JOINING_TYPE_D = 3, | |||
| 75 | JOINING_TYPE_C = JOINING_TYPE_D, | |||
| 76 | JOINING_GROUP_ALAPH = 4, | |||
| 77 | JOINING_GROUP_DALATH_RISH = 5, | |||
| 78 | NUM_STATE_MACHINE_COLS = 6, | |||
| 79 | ||||
| 80 | JOINING_TYPE_T = 7, | |||
| 81 | JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */ | |||
| 82 | }; | |||
| 83 | ||||
| 84 | #include "hb-ot-shape-complex-arabic-table.hh" | |||
| 85 | ||||
| 86 | static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat) | |||
| 87 | { | |||
| 88 | unsigned int j_type = joining_type(u); | |||
| 89 | if (likely (j_type != JOINING_TYPE_X)(__builtin_expect (!!(j_type != JOINING_TYPE_X), 1))) | |||
| 90 | return j_type; | |||
| 91 | ||||
| 92 | return (FLAG_UNSAFE(gen_cat)((unsigned)(gen_cat) < 32 ? (((uint32_t) 1U) << (unsigned )(gen_cat)) : 0) & | |||
| 93 | (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ))) | | |||
| 94 | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ))) | | |||
| 95 | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT)(static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_FORMAT ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_FORMAT )))) | |||
| 96 | ) ? JOINING_TYPE_T : JOINING_TYPE_U; | |||
| 97 | } | |||
| 98 | ||||
| 99 | #define FEATURE_IS_SYRIAC(tag)hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3') hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3') | |||
| 100 | ||||
| 101 | static const hb_tag_t arabic_features[] = | |||
| 102 | { | |||
| 103 | HB_TAG('i','s','o','l')((hb_tag_t)((((uint32_t)('i')&0xFF)<<24)|(((uint32_t )('s')&0xFF)<<16)|(((uint32_t)('o')&0xFF)<< 8)|((uint32_t)('l')&0xFF))), | |||
| 104 | HB_TAG('f','i','n','a')((hb_tag_t)((((uint32_t)('f')&0xFF)<<24)|(((uint32_t )('i')&0xFF)<<16)|(((uint32_t)('n')&0xFF)<< 8)|((uint32_t)('a')&0xFF))), | |||
| 105 | HB_TAG('f','i','n','2')((hb_tag_t)((((uint32_t)('f')&0xFF)<<24)|(((uint32_t )('i')&0xFF)<<16)|(((uint32_t)('n')&0xFF)<< 8)|((uint32_t)('2')&0xFF))), | |||
| 106 | HB_TAG('f','i','n','3')((hb_tag_t)((((uint32_t)('f')&0xFF)<<24)|(((uint32_t )('i')&0xFF)<<16)|(((uint32_t)('n')&0xFF)<< 8)|((uint32_t)('3')&0xFF))), | |||
| 107 | HB_TAG('m','e','d','i')((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('e')&0xFF)<<16)|(((uint32_t)('d')&0xFF)<< 8)|((uint32_t)('i')&0xFF))), | |||
| 108 | HB_TAG('m','e','d','2')((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('e')&0xFF)<<16)|(((uint32_t)('d')&0xFF)<< 8)|((uint32_t)('2')&0xFF))), | |||
| 109 | HB_TAG('i','n','i','t')((hb_tag_t)((((uint32_t)('i')&0xFF)<<24)|(((uint32_t )('n')&0xFF)<<16)|(((uint32_t)('i')&0xFF)<< 8)|((uint32_t)('t')&0xFF))), | |||
| 110 | HB_TAG_NONE((hb_tag_t)((((uint32_t)(0)&0xFF)<<24)|(((uint32_t) (0)&0xFF)<<16)|(((uint32_t)(0)&0xFF)<<8)| ((uint32_t)(0)&0xFF))) | |||
| 111 | }; | |||
| 112 | ||||
| 113 | ||||
| 114 | /* Same order as the feature array */ | |||
| 115 | enum arabic_action_t { | |||
| 116 | ISOL, | |||
| 117 | FINA, | |||
| 118 | FIN2, | |||
| 119 | FIN3, | |||
| 120 | MEDI, | |||
| 121 | MED2, | |||
| 122 | INIT, | |||
| 123 | ||||
| 124 | NONE, | |||
| 125 | ||||
| 126 | ARABIC_NUM_FEATURES = NONE, | |||
| 127 | ||||
| 128 | /* We abuse the same byte for other things... */ | |||
| 129 | STCH_FIXED, | |||
| 130 | STCH_REPEATING, | |||
| 131 | }; | |||
| 132 | ||||
| 133 | static const struct arabic_state_table_entry { | |||
| 134 | uint8_t prev_action; | |||
| 135 | uint8_t curr_action; | |||
| 136 | uint16_t next_state; | |||
| 137 | } arabic_state_table[][NUM_STATE_MACHINE_COLS] = | |||
| 138 | { | |||
| 139 | /* jt_U, jt_L, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */ | |||
| 140 | ||||
| 141 | /* State 0: prev was U, not willing to join. */ | |||
| 142 | { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, }, | |||
| 143 | ||||
| 144 | /* State 1: prev was R or ISOL/ALAPH, not willing to join. */ | |||
| 145 | { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, }, | |||
| 146 | ||||
| 147 | /* State 2: prev was D/L in ISOL form, willing to join. */ | |||
| 148 | { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, }, | |||
| 149 | ||||
| 150 | /* State 3: prev was D in FINA form, willing to join. */ | |||
| 151 | { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, }, | |||
| 152 | ||||
| 153 | /* State 4: prev was FINA ALAPH, not willing to join. */ | |||
| 154 | { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, }, | |||
| 155 | ||||
| 156 | /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */ | |||
| 157 | { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, }, | |||
| 158 | ||||
| 159 | /* State 6: prev was DALATH/RISH, not willing to join. */ | |||
| 160 | { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, } | |||
| 161 | }; | |||
| 162 | ||||
| 163 | ||||
| 164 | static void | |||
| 165 | arabic_fallback_shape (const hb_ot_shape_plan_t *plan, | |||
| 166 | hb_font_t *font, | |||
| 167 | hb_buffer_t *buffer); | |||
| 168 | ||||
| 169 | static void | |||
| 170 | record_stch (const hb_ot_shape_plan_t *plan, | |||
| 171 | hb_font_t *font, | |||
| 172 | hb_buffer_t *buffer); | |||
| 173 | ||||
| 174 | static void | |||
| 175 | collect_features_arabic (hb_ot_shape_planner_t *plan) | |||
| 176 | { | |||
| 177 | hb_ot_map_builder_t *map = &plan->map; | |||
| 178 | ||||
| 179 | /* We apply features according to the Arabic spec, with pauses | |||
| 180 | * in between most. | |||
| 181 | * | |||
| 182 | * The pause between init/medi/... and rlig is required. See eg: | |||
| 183 | * https://bugzilla.mozilla.org/show_bug.cgi?id=644184 | |||
| 184 | * | |||
| 185 | * The pauses between init/medi/... themselves are not necessarily | |||
| 186 | * needed as only one of those features is applied to any character. | |||
| 187 | * The only difference it makes is when fonts have contextual | |||
| 188 | * substitutions. We now follow the order of the spec, which makes | |||
| 189 | * for better experience if that's what Uniscribe is doing. | |||
| 190 | * | |||
| 191 | * At least for Arabic, looks like Uniscribe has a pause between | |||
| 192 | * rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't | |||
| 193 | * work. However, testing shows that rlig and calt are applied | |||
| 194 | * together for Mongolian in Uniscribe. As such, we only add a | |||
| 195 | * pause for Arabic, not other scripts. | |||
| 196 | * | |||
| 197 | * A pause after calt is required to make KFGQPC Uthmanic Script HAFS | |||
| 198 | * work correctly. See https://github.com/harfbuzz/harfbuzz/issues/505 | |||
| 199 | */ | |||
| 200 | ||||
| 201 | ||||
| 202 | map->enable_feature (HB_TAG('s','t','c','h')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t )('t')&0xFF)<<16)|(((uint32_t)('c')&0xFF)<< 8)|((uint32_t)('h')&0xFF)))); | |||
| 203 | map->add_gsub_pause (record_stch); | |||
| 204 | ||||
| 205 | map->enable_feature (HB_TAG('c','c','m','p')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t )('c')&0xFF)<<16)|(((uint32_t)('m')&0xFF)<< 8)|((uint32_t)('p')&0xFF)))); | |||
| 206 | map->enable_feature (HB_TAG('l','o','c','l')((hb_tag_t)((((uint32_t)('l')&0xFF)<<24)|(((uint32_t )('o')&0xFF)<<16)|(((uint32_t)('c')&0xFF)<< 8)|((uint32_t)('l')&0xFF)))); | |||
| 207 | ||||
| 208 | map->add_gsub_pause (nullptr); | |||
| 209 | ||||
| 210 | for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) | |||
| 211 | { | |||
| 212 | bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i])hb_in_range<unsigned char> ((unsigned char) (arabic_features [i]), '2', '3'); | |||
| 213 | map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE); | |||
| 214 | map->add_gsub_pause (nullptr); | |||
| 215 | } | |||
| 216 | ||||
| 217 | /* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script | |||
| 218 | * however, it says a ZWJ should also mean "don't ligate". So we run | |||
| 219 | * the main ligating features as MANUAL_ZWJ. */ | |||
| 220 | ||||
| 221 | map->enable_feature (HB_TAG('r','l','i','g')((hb_tag_t)((((uint32_t)('r')&0xFF)<<24)|(((uint32_t )('l')&0xFF)<<16)|(((uint32_t)('i')&0xFF)<< 8)|((uint32_t)('g')&0xFF))), F_MANUAL_ZWJ | F_HAS_FALLBACK); | |||
| 222 | ||||
| 223 | if (plan->props.script == HB_SCRIPT_ARABIC) | |||
| 224 | map->add_gsub_pause (arabic_fallback_shape); | |||
| 225 | ||||
| 226 | /* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */ | |||
| 227 | map->enable_feature (HB_TAG('r','c','l','t')((hb_tag_t)((((uint32_t)('r')&0xFF)<<24)|(((uint32_t )('c')&0xFF)<<16)|(((uint32_t)('l')&0xFF)<< 8)|((uint32_t)('t')&0xFF))), F_MANUAL_ZWJ); | |||
| 228 | map->enable_feature (HB_TAG('c','a','l','t')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t )('a')&0xFF)<<16)|(((uint32_t)('l')&0xFF)<< 8)|((uint32_t)('t')&0xFF))), F_MANUAL_ZWJ); | |||
| 229 | map->add_gsub_pause (nullptr); | |||
| 230 | ||||
| 231 | /* The spec includes 'cswh'. Earlier versions of Windows | |||
| 232 | * used to enable this by default, but testing suggests | |||
| 233 | * that Windows 8 and later do not enable it by default, | |||
| 234 | * and spec now says 'Off by default'. | |||
| 235 | * We disabled this in ae23c24c32. | |||
| 236 | * Note that IranNastaliq uses this feature extensively | |||
| 237 | * to fixup broken glyph sequences. Oh well... | |||
| 238 | * Test case: U+0643,U+0640,U+0631. */ | |||
| 239 | //map->enable_feature (HB_TAG('c','s','w','h')); | |||
| 240 | map->enable_feature (HB_TAG('m','s','e','t')((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('s')&0xFF)<<16)|(((uint32_t)('e')&0xFF)<< 8)|((uint32_t)('t')&0xFF)))); | |||
| 241 | } | |||
| 242 | ||||
| 243 | #include "hb-ot-shape-complex-arabic-fallback.hh" | |||
| 244 | ||||
| 245 | struct arabic_shape_plan_t | |||
| 246 | { | |||
| 247 | /* The "+ 1" in the next array is to accommodate for the "NONE" command, | |||
| 248 | * which is not an OpenType feature, but this simplifies the code by not | |||
| 249 | * having to do a "if (... < NONE) ..." and just rely on the fact that | |||
| 250 | * mask_array[NONE] == 0. */ | |||
| 251 | hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1]; | |||
| 252 | ||||
| 253 | hb_atomic_ptr_t<arabic_fallback_plan_t> fallback_plan; | |||
| 254 | ||||
| 255 | unsigned int do_fallback : 1; | |||
| 256 | unsigned int has_stch : 1; | |||
| 257 | }; | |||
| 258 | ||||
| 259 | void * | |||
| 260 | data_create_arabic (const hb_ot_shape_plan_t *plan) | |||
| 261 | { | |||
| 262 | arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t)); | |||
| 263 | if (unlikely (!arabic_plan)(__builtin_expect (!!(!arabic_plan), 0))) | |||
| 264 | return nullptr; | |||
| 265 | ||||
| 266 | arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC; | |||
| 267 | arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h')((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t )('t')&0xFF)<<16)|(((uint32_t)('c')&0xFF)<< 8)|((uint32_t)('h')&0xFF)))); | |||
| 268 | for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { | |||
| 269 | arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]); | |||
| 270 | arabic_plan->do_fallback = arabic_plan->do_fallback && | |||
| 271 | (FEATURE_IS_SYRIAC (arabic_features[i])hb_in_range<unsigned char> ((unsigned char) (arabic_features [i]), '2', '3') || | |||
| 272 | plan->map.needs_fallback (arabic_features[i])); | |||
| 273 | } | |||
| 274 | ||||
| 275 | return arabic_plan; | |||
| 276 | } | |||
| 277 | ||||
| 278 | void | |||
| 279 | data_destroy_arabic (void *data) | |||
| 280 | { | |||
| 281 | arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data; | |||
| 282 | ||||
| 283 | arabic_fallback_plan_destroy (arabic_plan->fallback_plan); | |||
| 284 | ||||
| 285 | free (data); | |||
| 286 | } | |||
| 287 | ||||
| 288 | static void | |||
| 289 | arabic_joining (hb_buffer_t *buffer) | |||
| 290 | { | |||
| 291 | unsigned int count = buffer->len; | |||
| 292 | hb_glyph_info_t *info = buffer->info; | |||
| 293 | unsigned int prev = UINT_MAX(2147483647 *2U +1U), state = 0; | |||
| 294 | ||||
| 295 | /* Check pre-context */ | |||
| 296 | for (unsigned int i = 0; i < buffer->context_len[0]; i++) | |||
| 297 | { | |||
| 298 | unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i])); | |||
| 299 | ||||
| 300 | if (unlikely (this_type == JOINING_TYPE_T)(__builtin_expect (!!(this_type == JOINING_TYPE_T), 0))) | |||
| 301 | continue; | |||
| 302 | ||||
| 303 | const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; | |||
| 304 | state = entry->next_state; | |||
| 305 | break; | |||
| 306 | } | |||
| 307 | ||||
| 308 | for (unsigned int i = 0; i < count; i++) | |||
| 309 | { | |||
| 310 | unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i])); | |||
| 311 | ||||
| 312 | if (unlikely (this_type == JOINING_TYPE_T)(__builtin_expect (!!(this_type == JOINING_TYPE_T), 0))) { | |||
| 313 | info[i].arabic_shaping_action()var2.u8[3] = NONE; | |||
| 314 | continue; | |||
| 315 | } | |||
| 316 | ||||
| 317 | const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; | |||
| 318 | ||||
| 319 | if (entry->prev_action != NONE && prev != UINT_MAX(2147483647 *2U +1U)) | |||
| 320 | { | |||
| 321 | info[prev].arabic_shaping_action()var2.u8[3] = entry->prev_action; | |||
| 322 | buffer->unsafe_to_break (prev, i + 1); | |||
| 323 | } | |||
| 324 | ||||
| 325 | info[i].arabic_shaping_action()var2.u8[3] = entry->curr_action; | |||
| 326 | ||||
| 327 | prev = i; | |||
| 328 | state = entry->next_state; | |||
| 329 | } | |||
| 330 | ||||
| 331 | for (unsigned int i = 0; i < buffer->context_len[1]; i++) | |||
| 332 | { | |||
| 333 | unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i])); | |||
| 334 | ||||
| 335 | if (unlikely (this_type == JOINING_TYPE_T)(__builtin_expect (!!(this_type == JOINING_TYPE_T), 0))) | |||
| 336 | continue; | |||
| 337 | ||||
| 338 | const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; | |||
| 339 | if (entry->prev_action != NONE && prev != UINT_MAX(2147483647 *2U +1U)) | |||
| 340 | info[prev].arabic_shaping_action()var2.u8[3] = entry->prev_action; | |||
| 341 | break; | |||
| 342 | } | |||
| 343 | } | |||
| 344 | ||||
| 345 | static void | |||
| 346 | mongolian_variation_selectors (hb_buffer_t *buffer) | |||
| 347 | { | |||
| 348 | /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */ | |||
| 349 | unsigned int count = buffer->len; | |||
| 350 | hb_glyph_info_t *info = buffer->info; | |||
| 351 | for (unsigned int i = 1; i < count; i++) | |||
| 352 | if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x180Bu, 0x180Du))(__builtin_expect (!!(hb_in_range<hb_codepoint_t> (info [i].codepoint, 0x180Bu, 0x180Du)), 0))) | |||
| 353 | info[i].arabic_shaping_action()var2.u8[3] = info[i - 1].arabic_shaping_action()var2.u8[3]; | |||
| 354 | } | |||
| 355 | ||||
| 356 | void | |||
| 357 | setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan, | |||
| 358 | hb_buffer_t *buffer, | |||
| 359 | hb_script_t script) | |||
| 360 | { | |||
| 361 | HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action)buffer->allocate_var (__builtin_offsetof(hb_glyph_info_t, var2 .u8[3]) - __builtin_offsetof(hb_glyph_info_t, var1), sizeof ( buffer->info[0].var2.u8[3])); | |||
| 362 | ||||
| 363 | arabic_joining (buffer); | |||
| 364 | if (script == HB_SCRIPT_MONGOLIAN) | |||
| 365 | mongolian_variation_selectors (buffer); | |||
| 366 | ||||
| 367 | unsigned int count = buffer->len; | |||
| 368 | hb_glyph_info_t *info = buffer->info; | |||
| 369 | for (unsigned int i = 0; i < count; i++) | |||
| 370 | info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()var2.u8[3]]; | |||
| 371 | } | |||
| 372 | ||||
| 373 | static void | |||
| 374 | setup_masks_arabic (const hb_ot_shape_plan_t *plan, | |||
| 375 | hb_buffer_t *buffer, | |||
| 376 | hb_font_t *font HB_UNUSED__attribute__((unused))) | |||
| 377 | { | |||
| 378 | const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; | |||
| 379 | setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script); | |||
| 380 | } | |||
| 381 | ||||
| 382 | static void | |||
| 383 | arabic_fallback_shape (const hb_ot_shape_plan_t *plan, | |||
| 384 | hb_font_t *font, | |||
| 385 | hb_buffer_t *buffer) | |||
| 386 | { | |||
| 387 | #ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK | |||
| 388 | return; | |||
| 389 | #endif | |||
| 390 | ||||
| 391 | const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; | |||
| 392 | ||||
| 393 | if (!arabic_plan->do_fallback) | |||
| ||||
| 394 | return; | |||
| 395 | ||||
| 396 | retry: | |||
| 397 | arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan; | |||
| 398 | if (unlikely (!fallback_plan)(__builtin_expect (!!(!fallback_plan), 0))) | |||
| 399 | { | |||
| 400 | /* This sucks. We need a font to build the fallback plan... */ | |||
| 401 | fallback_plan = arabic_fallback_plan_create (plan, font); | |||
| 402 | if (unlikely (!arabic_plan->fallback_plan.cmpexch (nullptr, fallback_plan))(__builtin_expect (!!(!arabic_plan->fallback_plan.cmpexch ( nullptr, fallback_plan)), 0))) | |||
| 403 | { | |||
| 404 | arabic_fallback_plan_destroy (fallback_plan); | |||
| 405 | goto retry; | |||
| 406 | } | |||
| 407 | } | |||
| 408 | ||||
| 409 | arabic_fallback_plan_shape (fallback_plan, font, buffer); | |||
| 410 | } | |||
| 411 | ||||
| 412 | /* | |||
| 413 | * Stretch feature: "stch". | |||
| 414 | * See example here: | |||
| 415 | * https://docs.microsoft.com/en-us/typography/script-development/syriac | |||
| 416 | * We implement this in a generic way, such that the Arabic subtending | |||
| 417 | * marks can use it as well. | |||
| 418 | */ | |||
| 419 | ||||
| 420 | static void | |||
| 421 | record_stch (const hb_ot_shape_plan_t *plan, | |||
| 422 | hb_font_t *font HB_UNUSED__attribute__((unused)), | |||
| 423 | hb_buffer_t *buffer) | |||
| 424 | { | |||
| 425 | const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; | |||
| 426 | if (!arabic_plan->has_stch) | |||
| 427 | return; | |||
| 428 | ||||
| 429 | /* 'stch' feature was just applied. Look for anything that multiplied, | |||
| 430 | * and record it for stch treatment later. Note that rtlm, frac, etc | |||
| 431 | * are applied before stch, but we assume that they didn't result in | |||
| 432 | * anything multiplying into 5 pieces, so it's safe-ish... */ | |||
| 433 | ||||
| 434 | unsigned int count = buffer->len; | |||
| 435 | hb_glyph_info_t *info = buffer->info; | |||
| 436 | for (unsigned int i = 0; i < count; i++) | |||
| 437 | if (unlikely (_hb_glyph_info_multiplied (&info[i]))(__builtin_expect (!!(_hb_glyph_info_multiplied (&info[i] )), 0))) | |||
| 438 | { | |||
| 439 | unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]); | |||
| 440 | info[i].arabic_shaping_action()var2.u8[3] = comp % 2 ? STCH_REPEATING : STCH_FIXED; | |||
| 441 | buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCHHB_BUFFER_SCRATCH_FLAG_COMPLEX0; | |||
| 442 | } | |||
| 443 | } | |||
| 444 | ||||
| 445 | static void | |||
| 446 | apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED__attribute__((unused)), | |||
| 447 | hb_buffer_t *buffer, | |||
| 448 | hb_font_t *font) | |||
| 449 | { | |||
| 450 | if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH))(__builtin_expect (!!(!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_COMPLEX0 )), 1))) | |||
| 451 | return; | |||
| 452 | ||||
| 453 | /* The Arabic shaper currently always processes in RTL mode, so we should | |||
| 454 | * stretch / position the stretched pieces to the left / preceding glyphs. */ | |||
| 455 | ||||
| 456 | /* We do a two pass implementation: | |||
| 457 | * First pass calculates the exact number of extra glyphs we need, | |||
| 458 | * We then enlarge buffer to have that much room, | |||
| 459 | * Second pass applies the stretch, copying things to the end of buffer. | |||
| 460 | */ | |||
| 461 | ||||
| 462 | int sign = font->x_scale < 0 ? -1 : +1; | |||
| 463 | unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT | |||
| 464 | enum { MEASURE, CUT } /* step_t */; | |||
| 465 | ||||
| 466 | for (unsigned int step = MEASURE; step <= CUT; step = step + 1) | |||
| 467 | { | |||
| 468 | unsigned int count = buffer->len; | |||
| 469 | hb_glyph_info_t *info = buffer->info; | |||
| 470 | hb_glyph_position_t *pos = buffer->pos; | |||
| 471 | unsigned int new_len = count + extra_glyphs_needed; // write head during CUT | |||
| 472 | unsigned int j = new_len; | |||
| 473 | for (unsigned int i = count; i; i--) | |||
| 474 | { | |||
| 475 | if (!hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action()var2.u8[3], STCH_FIXED, STCH_REPEATING)) | |||
| 476 | { | |||
| 477 | if (step == CUT) | |||
| 478 | { | |||
| 479 | --j; | |||
| 480 | info[j] = info[i - 1]; | |||
| 481 | pos[j] = pos[i - 1]; | |||
| 482 | } | |||
| 483 | continue; | |||
| 484 | } | |||
| 485 | ||||
| 486 | /* Yay, justification! */ | |||
| 487 | ||||
| 488 | hb_position_t w_total = 0; // Total to be filled | |||
| 489 | hb_position_t w_fixed = 0; // Sum of fixed tiles | |||
| 490 | hb_position_t w_repeating = 0; // Sum of repeating tiles | |||
| 491 | int n_fixed = 0; | |||
| 492 | int n_repeating = 0; | |||
| 493 | ||||
| 494 | unsigned int end = i; | |||
| 495 | while (i && | |||
| 496 | hb_in_range<uint8_t> (info[i - 1].arabic_shaping_action()var2.u8[3], STCH_FIXED, STCH_REPEATING)) | |||
| 497 | { | |||
| 498 | i--; | |||
| 499 | hb_position_t width = font->get_glyph_h_advance (info[i].codepoint); | |||
| 500 | if (info[i].arabic_shaping_action()var2.u8[3] == STCH_FIXED) | |||
| 501 | { | |||
| 502 | w_fixed += width; | |||
| 503 | n_fixed++; | |||
| 504 | } | |||
| 505 | else | |||
| 506 | { | |||
| 507 | w_repeating += width; | |||
| 508 | n_repeating++; | |||
| 509 | } | |||
| 510 | } | |||
| 511 | unsigned int start = i; | |||
| 512 | unsigned int context = i; | |||
| 513 | while (context && | |||
| 514 | !hb_in_range<uint8_t> (info[context - 1].arabic_shaping_action()var2.u8[3], STCH_FIXED, STCH_REPEATING) && | |||
| 515 | (_hb_glyph_info_is_default_ignorable (&info[context - 1]) || | |||
| 516 | HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))(((unsigned)(_hb_glyph_info_get_general_category (&info[context - 1])) < 32 ? (((uint32_t) 1U) << (unsigned)(_hb_glyph_info_get_general_category (&info[context - 1]))) : 0) & ((static_assert_expr< (unsigned)(HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) < 32> ::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL ))) | (static_assert_expr<(unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL ) < 32>::value + (((uint32_t) 1U) << (unsigned)(HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL ))))))) | |||
| 517 | { | |||
| 518 | context--; | |||
| 519 | w_total += pos[context].x_advance; | |||
| 520 | } | |||
| 521 | i++; // Don't touch i again. | |||
| 522 | ||||
| 523 | DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%d,%d,%d)",_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "%s stretch at (%d,%d,%d)", step == MEASURE ? "measuring" : "cutting", context, start, end) | |||
| 524 | step == MEASURE ? "measuring" : "cutting", context, start, end)_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "%s stretch at (%d,%d,%d)", step == MEASURE ? "measuring" : "cutting", context, start, end); | |||
| 525 | DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%d width %d", start - context, w_total)_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "rest of word: count=%d width %d", start - context , w_total); | |||
| 526 | DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%d", n_fixed, w_fixed)_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "fixed tiles: count=%d width=%d", n_fixed, w_fixed ); | |||
| 527 | DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating)_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "repeating tiles: count=%d width=%d", n_repeating, w_repeating ); | |||
| 528 | ||||
| 529 | /* Number of additional times to repeat each repeating tile. */ | |||
| 530 | int n_copies = 0; | |||
| 531 | ||||
| 532 | hb_position_t w_remaining = w_total - w_fixed; | |||
| 533 | if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0) | |||
| 534 | n_copies = (sign * w_remaining) / (sign * w_repeating) - 1; | |||
| 535 | ||||
| 536 | /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */ | |||
| 537 | hb_position_t extra_repeat_overlap = 0; | |||
| 538 | hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1); | |||
| 539 | if (shortfall > 0 && n_repeating > 0) | |||
| 540 | { | |||
| 541 | ++n_copies; | |||
| 542 | hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining; | |||
| 543 | if (excess > 0) | |||
| 544 | extra_repeat_overlap = excess / (n_copies * n_repeating); | |||
| 545 | } | |||
| 546 | ||||
| 547 | if (step == MEASURE) | |||
| 548 | { | |||
| 549 | extra_glyphs_needed += n_copies * n_repeating; | |||
| 550 | DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies)_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "will add extra %d copies of repeating tiles", n_copies ); | |||
| 551 | } | |||
| 552 | else | |||
| 553 | { | |||
| 554 | buffer->unsafe_to_break (context, end); | |||
| 555 | hb_position_t x_offset = 0; | |||
| 556 | for (unsigned int k = end; k > start; k--) | |||
| 557 | { | |||
| 558 | hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint); | |||
| 559 | ||||
| 560 | unsigned int repeat = 1; | |||
| 561 | if (info[k - 1].arabic_shaping_action()var2.u8[3] == STCH_REPEATING) | |||
| 562 | repeat += n_copies; | |||
| 563 | ||||
| 564 | DEBUG_MSG (ARABIC, nullptr, "appending %d copies of glyph %d; j=%d",_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "appending %d copies of glyph %d; j=%d", repeat, info [k - 1].codepoint, j) | |||
| 565 | repeat, info[k - 1].codepoint, j)_hb_debug_msg<(0 +0)> ("ARABIC", (nullptr), nullptr, false , 0, 0, "appending %d copies of glyph %d; j=%d", repeat, info [k - 1].codepoint, j); | |||
| 566 | for (unsigned int n = 0; n < repeat; n++) | |||
| 567 | { | |||
| 568 | x_offset -= width; | |||
| 569 | if (n > 0) | |||
| 570 | x_offset += extra_repeat_overlap; | |||
| 571 | pos[k - 1].x_offset = x_offset; | |||
| 572 | /* Append copy. */ | |||
| 573 | --j; | |||
| 574 | info[j] = info[k - 1]; | |||
| 575 | pos[j] = pos[k - 1]; | |||
| 576 | } | |||
| 577 | } | |||
| 578 | } | |||
| 579 | } | |||
| 580 | ||||
| 581 | if (step == MEASURE) | |||
| 582 | { | |||
| 583 | if (unlikely (!buffer->ensure (count + extra_glyphs_needed))(__builtin_expect (!!(!buffer->ensure (count + extra_glyphs_needed )), 0))) | |||
| 584 | break; | |||
| 585 | } | |||
| 586 | else | |||
| 587 | { | |||
| 588 | assert (j == 0)(static_cast <bool> (j == 0) ? void (0) : __assert_fail ("j == 0", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc" , 588, __extension__ __PRETTY_FUNCTION__)); | |||
| 589 | buffer->len = new_len; | |||
| 590 | } | |||
| 591 | } | |||
| 592 | } | |||
| 593 | ||||
| 594 | ||||
| 595 | static void | |||
| 596 | postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan, | |||
| 597 | hb_buffer_t *buffer, | |||
| 598 | hb_font_t *font) | |||
| 599 | { | |||
| 600 | apply_stch (plan, buffer, font); | |||
| 601 | ||||
| 602 | HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action)buffer->deallocate_var (__builtin_offsetof(hb_glyph_info_t , var2.u8[3]) - __builtin_offsetof(hb_glyph_info_t, var1), sizeof (buffer->info[0].var2.u8[3])); | |||
| 603 | } | |||
| 604 | ||||
| 605 | /* https://www.unicode.org/reports/tr53/ */ | |||
| 606 | ||||
| 607 | static hb_codepoint_t | |||
| 608 | modifier_combining_marks[] = | |||
| 609 | { | |||
| 610 | 0x0654u, /* ARABIC HAMZA ABOVE */ | |||
| 611 | 0x0655u, /* ARABIC HAMZA BELOW */ | |||
| 612 | 0x0658u, /* ARABIC MARK NOON GHUNNA */ | |||
| 613 | 0x06DCu, /* ARABIC SMALL HIGH SEEN */ | |||
| 614 | 0x06E3u, /* ARABIC SMALL LOW SEEN */ | |||
| 615 | 0x06E7u, /* ARABIC SMALL HIGH YEH */ | |||
| 616 | 0x06E8u, /* ARABIC SMALL HIGH NOON */ | |||
| 617 | 0x08D3u, /* ARABIC SMALL LOW WAW */ | |||
| 618 | 0x08F3u, /* ARABIC SMALL HIGH WAW */ | |||
| 619 | }; | |||
| 620 | ||||
| 621 | static inline bool | |||
| 622 | info_is_mcm (const hb_glyph_info_t &info) | |||
| 623 | { | |||
| 624 | hb_codepoint_t u = info.codepoint; | |||
| 625 | for (unsigned int i = 0; i < ARRAY_LENGTH (modifier_combining_marks); i++) | |||
| 626 | if (u == modifier_combining_marks[i]) | |||
| 627 | return true; | |||
| 628 | return false; | |||
| 629 | } | |||
| 630 | ||||
| 631 | static void | |||
| 632 | reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED__attribute__((unused)), | |||
| 633 | hb_buffer_t *buffer, | |||
| 634 | unsigned int start, | |||
| 635 | unsigned int end) | |||
| 636 | { | |||
| 637 | hb_glyph_info_t *info = buffer->info; | |||
| 638 | ||||
| 639 | DEBUG_MSG (ARABIC, buffer, "Reordering marks from %d to %d", start, end)_hb_debug_msg<(0 +0)> ("ARABIC", (buffer), nullptr, false , 0, 0, "Reordering marks from %d to %d", start, end); | |||
| 640 | ||||
| 641 | unsigned int i = start; | |||
| 642 | for (unsigned int cc = 220; cc <= 230; cc += 10) | |||
| 643 | { | |||
| 644 | DEBUG_MSG (ARABIC, buffer, "Looking for %d's starting at %d", cc, i)_hb_debug_msg<(0 +0)> ("ARABIC", (buffer), nullptr, false , 0, 0, "Looking for %d's starting at %d", cc, i); | |||
| 645 | while (i < end && info_cc(info[i])(_hb_glyph_info_get_modified_combining_class (&(info[i])) ) < cc) | |||
| 646 | i++; | |||
| 647 | DEBUG_MSG (ARABIC, buffer, "Looking for %d's stopped at %d", cc, i)_hb_debug_msg<(0 +0)> ("ARABIC", (buffer), nullptr, false , 0, 0, "Looking for %d's stopped at %d", cc, i); | |||
| 648 | ||||
| 649 | if (i == end) | |||
| 650 | break; | |||
| 651 | ||||
| 652 | if (info_cc(info[i])(_hb_glyph_info_get_modified_combining_class (&(info[i])) ) > cc) | |||
| 653 | continue; | |||
| 654 | ||||
| 655 | unsigned int j = i; | |||
| 656 | while (j < end && info_cc(info[j])(_hb_glyph_info_get_modified_combining_class (&(info[j])) ) == cc && info_is_mcm (info[j])) | |||
| 657 | j++; | |||
| 658 | ||||
| 659 | if (i == j) | |||
| 660 | continue; | |||
| 661 | ||||
| 662 | DEBUG_MSG (ARABIC, buffer, "Found %d's from %d to %d", cc, i, j)_hb_debug_msg<(0 +0)> ("ARABIC", (buffer), nullptr, false , 0, 0, "Found %d's from %d to %d", cc, i, j); | |||
| 663 | ||||
| 664 | /* Shift it! */ | |||
| 665 | DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d", cc, i, j)_hb_debug_msg<(0 +0)> ("ARABIC", (buffer), nullptr, false , 0, 0, "Shifting %d's: %d %d", cc, i, j); | |||
| 666 | hb_glyph_info_t temp[HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS32]; | |||
| 667 | assert (j - i <= ARRAY_LENGTH (temp))(static_cast <bool> (j - i <= ARRAY_LENGTH (temp)) ? void (0) : __assert_fail ("j - i <= ARRAY_LENGTH (temp)", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc" , 667, __extension__ __PRETTY_FUNCTION__)); | |||
| 668 | buffer->merge_clusters (start, j); | |||
| 669 | memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t)); | |||
| 670 | memmove (&info[start + j - i], &info[start], (i - start) * sizeof (hb_glyph_info_t)); | |||
| 671 | memmove (&info[start], temp, (j - i) * sizeof (hb_glyph_info_t)); | |||
| 672 | ||||
| 673 | /* Renumber CC such that the reordered sequence is still sorted. | |||
| 674 | * 22 and 26 are chosen because they are smaller than all Arabic categories, | |||
| 675 | * and are folded back to 220/230 respectively during fallback mark positioning. | |||
| 676 | * | |||
| 677 | * We do this because the CGJ-handling logic in the normalizer relies on | |||
| 678 | * mark sequences having an increasing order even after this reordering. | |||
| 679 | * https://github.com/harfbuzz/harfbuzz/issues/554 | |||
| 680 | * This, however, does break some obscure sequences, where the normalizer | |||
| 681 | * might compose a sequence that it should not. For example, in the seequence | |||
| 682 | * ALEF, HAMZAH, MADDAH, we should NOT try to compose ALEF+MADDAH, but with this | |||
| 683 | * renumbering, we will. | |||
| 684 | */ | |||
| 685 | unsigned int new_start = start + j - i; | |||
| 686 | unsigned int new_cc = cc == 220 ? HB_MODIFIED_COMBINING_CLASS_CCC2225 : HB_MODIFIED_COMBINING_CLASS_CCC2626; | |||
| 687 | while (start < new_start) | |||
| 688 | { | |||
| 689 | _hb_glyph_info_set_modified_combining_class (&info[start], new_cc); | |||
| 690 | start++; | |||
| 691 | } | |||
| 692 | ||||
| 693 | i = j; | |||
| 694 | } | |||
| 695 | } | |||
| 696 | ||||
| 697 | const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = | |||
| 698 | { | |||
| 699 | collect_features_arabic, | |||
| 700 | nullptr, /* override_features */ | |||
| 701 | data_create_arabic, | |||
| 702 | data_destroy_arabic, | |||
| 703 | nullptr, /* preprocess_text */ | |||
| 704 | postprocess_glyphs_arabic, | |||
| 705 | HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, | |||
| 706 | nullptr, /* decompose */ | |||
| 707 | nullptr, /* compose */ | |||
| 708 | setup_masks_arabic, | |||
| 709 | HB_TAG_NONE((hb_tag_t)((((uint32_t)(0)&0xFF)<<24)|(((uint32_t) (0)&0xFF)<<16)|(((uint32_t)(0)&0xFF)<<8)| ((uint32_t)(0)&0xFF))), /* gpos_tag */ | |||
| 710 | reorder_marks_arabic, | |||
| 711 | HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, | |||
| 712 | true, /* fallback_position */ | |||
| 713 | }; | |||
| 714 | ||||
| 715 | ||||
| 716 | #endif |
| 1 | /* | ||||
| 2 | * Copyright © 2012 Google, Inc. | ||||
| 3 | * | ||||
| 4 | * This is part of HarfBuzz, a text shaping library. | ||||
| 5 | * | ||||
| 6 | * Permission is hereby granted, without written agreement and without | ||||
| 7 | * license or royalty fees, to use, copy, modify, and distribute this | ||||
| 8 | * software and its documentation for any purpose, provided that the | ||||
| 9 | * above copyright notice and the following two paragraphs appear in | ||||
| 10 | * all copies of this software. | ||||
| 11 | * | ||||
| 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | ||||
| 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | ||||
| 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | ||||
| 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | ||||
| 16 | * DAMAGE. | ||||
| 17 | * | ||||
| 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | ||||
| 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||||
| 20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | ||||
| 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | ||||
| 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | ||||
| 23 | * | ||||
| 24 | * Google Author(s): Behdad Esfahbod | ||||
| 25 | */ | ||||
| 26 | |||||
| 27 | #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH | ||||
| 28 | #define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH | ||||
| 29 | |||||
| 30 | #include "hb.hh" | ||||
| 31 | |||||
| 32 | #include "hb-ot-shape.hh" | ||||
| 33 | #include "hb-ot-layout-gsub-table.hh" | ||||
| 34 | |||||
| 35 | |||||
| 36 | /* Features ordered the same as the entries in shaping_table rows, | ||||
| 37 | * followed by rlig. Don't change. */ | ||||
| 38 | static const hb_tag_t arabic_fallback_features[] = | ||||
| 39 | { | ||||
| 40 | HB_TAG('i','n','i','t')((hb_tag_t)((((uint32_t)('i')&0xFF)<<24)|(((uint32_t )('n')&0xFF)<<16)|(((uint32_t)('i')&0xFF)<< 8)|((uint32_t)('t')&0xFF))), | ||||
| 41 | HB_TAG('m','e','d','i')((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('e')&0xFF)<<16)|(((uint32_t)('d')&0xFF)<< 8)|((uint32_t)('i')&0xFF))), | ||||
| 42 | HB_TAG('f','i','n','a')((hb_tag_t)((((uint32_t)('f')&0xFF)<<24)|(((uint32_t )('i')&0xFF)<<16)|(((uint32_t)('n')&0xFF)<< 8)|((uint32_t)('a')&0xFF))), | ||||
| 43 | HB_TAG('i','s','o','l')((hb_tag_t)((((uint32_t)('i')&0xFF)<<24)|(((uint32_t )('s')&0xFF)<<16)|(((uint32_t)('o')&0xFF)<< 8)|((uint32_t)('l')&0xFF))), | ||||
| 44 | HB_TAG('r','l','i','g')((hb_tag_t)((((uint32_t)('r')&0xFF)<<24)|(((uint32_t )('l')&0xFF)<<16)|(((uint32_t)('i')&0xFF)<< 8)|((uint32_t)('g')&0xFF))), | ||||
| 45 | }; | ||||
| 46 | |||||
| 47 | static OT::SubstLookup * | ||||
| 48 | arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED__attribute__((unused)), | ||||
| 49 | hb_font_t *font, | ||||
| 50 | unsigned int feature_index) | ||||
| 51 | { | ||||
| 52 | OT::HBGlyphID glyphs[SHAPING_TABLE_LAST0x06D3u - SHAPING_TABLE_FIRST0x0621u + 1]; | ||||
| 53 | OT::HBGlyphID substitutes[SHAPING_TABLE_LAST0x06D3u - SHAPING_TABLE_FIRST0x0621u + 1]; | ||||
| 54 | unsigned int num_glyphs = 0; | ||||
| 55 | |||||
| 56 | /* Populate arrays */ | ||||
| 57 | for (hb_codepoint_t u = SHAPING_TABLE_FIRST0x0621u; u < SHAPING_TABLE_LAST0x06D3u + 1; u++) | ||||
| 58 | { | ||||
| 59 | hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST0x0621u][feature_index]; | ||||
| 60 | hb_codepoint_t u_glyph, s_glyph; | ||||
| 61 | |||||
| 62 | if (!s || | ||||
| 63 | !hb_font_get_glyph (font, u, 0, &u_glyph) || | ||||
| 64 | !hb_font_get_glyph (font, s, 0, &s_glyph) || | ||||
| 65 | u_glyph == s_glyph || | ||||
| 66 | u_glyph > 0xFFFFu || s_glyph > 0xFFFFu) | ||||
| 67 | continue; | ||||
| 68 | |||||
| 69 | glyphs[num_glyphs] = u_glyph; | ||||
| 70 | substitutes[num_glyphs] = s_glyph; | ||||
| 71 | |||||
| 72 | num_glyphs++; | ||||
| 73 | } | ||||
| 74 | |||||
| 75 | if (!num_glyphs) | ||||
| 76 | return nullptr; | ||||
| 77 | |||||
| 78 | /* Bubble-sort or something equally good! | ||||
| 79 | * May not be good-enough for presidential candidate interviews, but good-enough for us... */ | ||||
| 80 | hb_stable_sort (&glyphs[0], num_glyphs, | ||||
| 81 | (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp, | ||||
| 82 | &substitutes[0]); | ||||
| 83 | |||||
| 84 | |||||
| 85 | /* Each glyph takes four bytes max, and there's some overhead. */ | ||||
| 86 | char buf[(SHAPING_TABLE_LAST0x06D3u - SHAPING_TABLE_FIRST0x0621u + 1) * 4 + 128]; | ||||
| 87 | hb_serialize_context_t c (buf, sizeof (buf)); | ||||
| 88 | OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); | ||||
| 89 | bool ret = lookup->serialize_single (&c, | ||||
| 90 | OT::LookupFlag::IgnoreMarks, | ||||
| 91 | hb_sorted_array (glyphs, num_glyphs), | ||||
| 92 | hb_array (substitutes, num_glyphs)); | ||||
| 93 | c.end_serialize (); | ||||
| 94 | |||||
| 95 | return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr; | ||||
| 96 | } | ||||
| 97 | |||||
| 98 | static OT::SubstLookup * | ||||
| 99 | arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED__attribute__((unused)), | ||||
| 100 | hb_font_t *font) | ||||
| 101 | { | ||||
| 102 | OT::HBGlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)((signed int) (sizeof (ligature_table) / sizeof (ligature_table [0])))]; | ||||
| 103 | unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)((signed int) (sizeof (ligature_table) / sizeof (ligature_table [0])))]; | ||||
| 104 | unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)((signed int) (sizeof (first_glyphs) / sizeof (first_glyphs[0 ])))]; | ||||
| 105 | unsigned int num_first_glyphs = 0; | ||||
| 106 | |||||
| 107 | /* We know that all our ligatures are 2-component */ | ||||
| 108 | OT::HBGlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs)((signed int) (sizeof (first_glyphs) / sizeof (first_glyphs[0 ]))) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)((signed int) (sizeof (ligature_table[0].ligatures) / sizeof ( ligature_table[0].ligatures[0])))]; | ||||
| 109 | unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)((signed int) (sizeof (ligature_list) / sizeof (ligature_list [0])))]; | ||||
| 110 | OT::HBGlyphID component_list[ARRAY_LENGTH_CONST (ligature_list)((signed int) (sizeof (ligature_list) / sizeof (ligature_list [0]))) * 1/* One extra component per ligature */]; | ||||
| 111 | unsigned int num_ligatures = 0; | ||||
| 112 | |||||
| 113 | /* Populate arrays */ | ||||
| 114 | |||||
| 115 | /* Sort out the first-glyphs */ | ||||
| 116 | for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++) | ||||
| 117 | { | ||||
| 118 | hb_codepoint_t first_u = ligature_table[first_glyph_idx].first; | ||||
| 119 | hb_codepoint_t first_glyph; | ||||
| 120 | if (!hb_font_get_glyph (font, first_u, 0, &first_glyph)) | ||||
| 121 | continue; | ||||
| 122 | first_glyphs[num_first_glyphs] = first_glyph; | ||||
| 123 | ligature_per_first_glyph_count_list[num_first_glyphs] = 0; | ||||
| 124 | first_glyphs_indirection[num_first_glyphs] = first_glyph_idx; | ||||
| 125 | num_first_glyphs++; | ||||
| 126 | } | ||||
| 127 | hb_stable_sort (&first_glyphs[0], num_first_glyphs, | ||||
| 128 | (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp, | ||||
| 129 | &first_glyphs_indirection[0]); | ||||
| 130 | |||||
| 131 | /* Now that the first-glyphs are sorted, walk again, populate ligatures. */ | ||||
| 132 | for (unsigned int i = 0; i < num_first_glyphs; i++) | ||||
| 133 | { | ||||
| 134 | unsigned int first_glyph_idx = first_glyphs_indirection[i]; | ||||
| 135 | |||||
| 136 | for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++) | ||||
| 137 | { | ||||
| 138 | hb_codepoint_t second_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second; | ||||
| 139 | hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature; | ||||
| 140 | hb_codepoint_t second_glyph, ligature_glyph; | ||||
| 141 | if (!second_u || | ||||
| 142 | !hb_font_get_glyph (font, second_u, 0, &second_glyph) || | ||||
| 143 | !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph)) | ||||
| 144 | continue; | ||||
| 145 | |||||
| 146 | ligature_per_first_glyph_count_list[i]++; | ||||
| 147 | |||||
| 148 | ligature_list[num_ligatures] = ligature_glyph; | ||||
| 149 | component_count_list[num_ligatures] = 2; | ||||
| 150 | component_list[num_ligatures] = second_glyph; | ||||
| 151 | num_ligatures++; | ||||
| 152 | } | ||||
| 153 | } | ||||
| 154 | |||||
| 155 | if (!num_ligatures) | ||||
| 156 | return nullptr; | ||||
| 157 | |||||
| 158 | |||||
| 159 | /* 16 bytes per ligature ought to be enough... */ | ||||
| 160 | char buf[ARRAY_LENGTH_CONST (ligature_list)((signed int) (sizeof (ligature_list) / sizeof (ligature_list [0]))) * 16 + 128]; | ||||
| 161 | hb_serialize_context_t c (buf, sizeof (buf)); | ||||
| 162 | OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); | ||||
| 163 | bool ret = lookup->serialize_ligature (&c, | ||||
| 164 | OT::LookupFlag::IgnoreMarks, | ||||
| 165 | hb_sorted_array (first_glyphs, num_first_glyphs), | ||||
| 166 | hb_array (ligature_per_first_glyph_count_list, num_first_glyphs), | ||||
| 167 | hb_array (ligature_list, num_ligatures), | ||||
| 168 | hb_array (component_count_list, num_ligatures), | ||||
| 169 | hb_array (component_list, num_ligatures)); | ||||
| 170 | c.end_serialize (); | ||||
| 171 | /* TODO sanitize the results? */ | ||||
| 172 | |||||
| 173 | return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr; | ||||
| 174 | } | ||||
| 175 | |||||
| 176 | static OT::SubstLookup * | ||||
| 177 | arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan, | ||||
| 178 | hb_font_t *font, | ||||
| 179 | unsigned int feature_index) | ||||
| 180 | { | ||||
| 181 | if (feature_index < 4) | ||||
| 182 | return arabic_fallback_synthesize_lookup_single (plan, font, feature_index); | ||||
| 183 | else | ||||
| 184 | return arabic_fallback_synthesize_lookup_ligature (plan, font); | ||||
| 185 | } | ||||
| 186 | |||||
| 187 | #define ARABIC_FALLBACK_MAX_LOOKUPS5 5 | ||||
| 188 | |||||
| 189 | struct arabic_fallback_plan_t | ||||
| 190 | { | ||||
| 191 | unsigned int num_lookups; | ||||
| 192 | bool free_lookups; | ||||
| 193 | |||||
| 194 | hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS5]; | ||||
| 195 | OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS5]; | ||||
| 196 | OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS5]; | ||||
| 197 | }; | ||||
| 198 | |||||
| 199 | #if defined(_WIN32) && !defined(HB_NO_WIN1256) | ||||
| 200 | #define HB_WITH_WIN1256 | ||||
| 201 | #endif | ||||
| 202 | |||||
| 203 | #ifdef HB_WITH_WIN1256 | ||||
| 204 | #include "hb-ot-shape-complex-arabic-win1256.hh" | ||||
| 205 | #endif | ||||
| 206 | |||||
| 207 | struct ManifestLookup | ||||
| 208 | { | ||||
| 209 | public: | ||||
| 210 | OT::Tag tag; | ||||
| 211 | OT::OffsetTo<OT::SubstLookup> lookupOffset; | ||||
| 212 | public: | ||||
| 213 | DEFINE_SIZE_STATIC (6)void _instance_assertion_on_line_213 () const { static_assert ((sizeof (*this) == (6)), ""); } unsigned int get_size () const { return (6); } static constexpr unsigned null_size = (6); static constexpr unsigned min_size = (6); static constexpr unsigned static_size = (6); | ||||
| 214 | }; | ||||
| 215 | typedef OT::ArrayOf<ManifestLookup> Manifest; | ||||
| 216 | |||||
| 217 | static bool | ||||
| 218 | arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED__attribute__((unused)), | ||||
| 219 | const hb_ot_shape_plan_t *plan HB_UNUSED__attribute__((unused)), | ||||
| 220 | hb_font_t *font HB_UNUSED__attribute__((unused))) | ||||
| 221 | { | ||||
| 222 | #ifdef HB_WITH_WIN1256 | ||||
| 223 | /* Does this font look like it's Windows-1256-encoded? */ | ||||
| 224 | hb_codepoint_t g; | ||||
| 225 | if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ && | ||||
| 226 | hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ && | ||||
| 227 | hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ && | ||||
| 228 | hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ && | ||||
| 229 | hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */)) | ||||
| 230 | return false; | ||||
| 231 | |||||
| 232 | const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest); | ||||
| 233 | static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) == | ||||
| 234 | ARABIC_FALLBACK_MAX_LOOKUPS5 * sizeof (ManifestLookup), ""); | ||||
| 235 | /* TODO sanitize the table? */ | ||||
| 236 | |||||
| 237 | unsigned j = 0; | ||||
| 238 | unsigned int count = manifest.len; | ||||
| 239 | for (unsigned int i = 0; i < count; i++) | ||||
| 240 | { | ||||
| 241 | fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag); | ||||
| 242 | if (fallback_plan->mask_array[j]) | ||||
| 243 | { | ||||
| 244 | fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset)); | ||||
| 245 | if (fallback_plan->lookup_array[j]) | ||||
| 246 | { | ||||
| 247 | fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]); | ||||
| 248 | j++; | ||||
| 249 | } | ||||
| 250 | } | ||||
| 251 | } | ||||
| 252 | |||||
| 253 | fallback_plan->num_lookups = j; | ||||
| 254 | fallback_plan->free_lookups = false; | ||||
| 255 | |||||
| 256 | return j > 0; | ||||
| 257 | #else | ||||
| 258 | return false; | ||||
| 259 | #endif | ||||
| 260 | } | ||||
| 261 | |||||
| 262 | static bool | ||||
| 263 | arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan, | ||||
| 264 | const hb_ot_shape_plan_t *plan, | ||||
| 265 | hb_font_t *font) | ||||
| 266 | { | ||||
| 267 | static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features)((signed int) (sizeof (arabic_fallback_features) / sizeof (arabic_fallback_features [0]))) <= ARABIC_FALLBACK_MAX_LOOKUPS5), ""); | ||||
| 268 | unsigned int j = 0; | ||||
| 269 | for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++) | ||||
| 270 | { | ||||
| 271 | fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]); | ||||
| 272 | if (fallback_plan->mask_array[j]) | ||||
| 273 | { | ||||
| 274 | fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i); | ||||
| 275 | if (fallback_plan->lookup_array[j]) | ||||
| 276 | { | ||||
| 277 | fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]); | ||||
| 278 | j++; | ||||
| 279 | } | ||||
| 280 | } | ||||
| 281 | } | ||||
| 282 | |||||
| 283 | fallback_plan->num_lookups = j; | ||||
| 284 | fallback_plan->free_lookups = true; | ||||
| 285 | |||||
| 286 | return j > 0; | ||||
| 287 | } | ||||
| 288 | |||||
| 289 | static arabic_fallback_plan_t * | ||||
| 290 | arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, | ||||
| 291 | hb_font_t *font) | ||||
| 292 | { | ||||
| 293 | arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t)); | ||||
| 294 | if (unlikely (!fallback_plan)(__builtin_expect (!!(!fallback_plan), 0))) | ||||
| 295 | return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t)NullHelper<arabic_fallback_plan_t>::get_null ()); | ||||
| 296 | |||||
| 297 | fallback_plan->num_lookups = 0; | ||||
| 298 | fallback_plan->free_lookups = false; | ||||
| 299 | |||||
| 300 | /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms, | ||||
| 301 | * in case the font has cmap entries for the presentation-forms characters. */ | ||||
| 302 | if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font)) | ||||
| 303 | return fallback_plan; | ||||
| 304 | |||||
| 305 | /* See if this looks like a Windows-1256-encoded font. If it does, use a | ||||
| 306 | * hand-coded GSUB table. */ | ||||
| 307 | if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font)) | ||||
| 308 | return fallback_plan; | ||||
| 309 | |||||
| 310 | assert (fallback_plan->num_lookups == 0)(static_cast <bool> (fallback_plan->num_lookups == 0 ) ? void (0) : __assert_fail ("fallback_plan->num_lookups == 0" , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh" , 310, __extension__ __PRETTY_FUNCTION__)); | ||||
| 311 | free (fallback_plan); | ||||
| 312 | return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t)NullHelper<arabic_fallback_plan_t>::get_null ()); | ||||
| 313 | } | ||||
| 314 | |||||
| 315 | static void | ||||
| 316 | arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan) | ||||
| 317 | { | ||||
| 318 | if (!fallback_plan
| ||||
| 319 | return; | ||||
| 320 | |||||
| 321 | for (unsigned int i = 0; i
| ||||
| 322 | if (fallback_plan->lookup_array[i]) | ||||
| 323 | { | ||||
| 324 | fallback_plan->accel_array[i].fini (); | ||||
| 325 | if (fallback_plan->free_lookups) | ||||
| 326 | free (fallback_plan->lookup_array[i]); | ||||
| 327 | } | ||||
| 328 | |||||
| 329 | free (fallback_plan); | ||||
| |||||
| 330 | } | ||||
| 331 | |||||
| 332 | static void | ||||
| 333 | arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, | ||||
| 334 | hb_font_t *font, | ||||
| 335 | hb_buffer_t *buffer) | ||||
| 336 | { | ||||
| 337 | OT::hb_ot_apply_context_t c (0, font, buffer); | ||||
| 338 | for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) | ||||
| 339 | if (fallback_plan->lookup_array[i]) { | ||||
| 340 | c.set_lookup_mask (fallback_plan->mask_array[i]); | ||||
| 341 | hb_ot_layout_substitute_lookup (&c, | ||||
| 342 | *fallback_plan->lookup_array[i], | ||||
| 343 | fallback_plan->accel_array[i]); | ||||
| 344 | } | ||||
| 345 | } | ||||
| 346 | |||||
| 347 | |||||
| 348 | #endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */ |