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 */ |