1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** GUIX Component */
16 /** */
17 /** Utility (Utility) */
18 /** */
19 /**************************************************************************/
20 #define GX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "gx_api.h"
26 #include "gx_utility.h"
27 #include "gx_system.h"
28
29 #if defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT)
30 #if defined(GX_DYNAMIC_ARABIC_SHAPING_SUPPORT)
31 /* Define joining types. */
32 #define JOINING_TYPE_NONE 0x01
33 #define JOINING_TYPE_RIGHT 0x02
34 #define JOINING_TYPE_LEFT 0x03
35 #define JOINING_TYPE_DUAL 0x04
36 #define JOINING_TYPE_CAUSING 0x05
37 #define JOINING_TYPE_TRANSPARENT 0x06
38
39 #define ARABIC_FORM_ISOLATED 0x01
40 #define ARABIC_FORM_INITIAL 0x02
41 #define ARABIC_FORM_FINAL 0x03
42 #define ARABIC_FORM_MEDIAL 0x04
43
44 typedef struct ARABIC_SHAPING_STRUCT
45 {
46 ULONG range_start;
47 ULONG range_end;
48 ULONG joining_type;
49 } ARABIC_SHAPING;
50
51 typedef struct ARABIC_FORM_STRUCT
52 {
53 ULONG code_point;
54 ULONG isolated;
55 ULONG final;
56 ULONG initial;
57 ULONG medial;
58 } ARABIC_FORM;
59
60 typedef struct ARABIC_LIGATURE_STRICT
61 {
62 ULONG alef;
63 ULONG lam;
64 ULONG ligature;
65 } ARABIC_LIGATURE;
66
67 typedef struct ARABIC_UNIT_STRUCT
68 {
69 ULONG code_point;
70 ULONG joining_type;
71 ULONG shape_form;
72 } ARABIC_UNIT;
73
74 static ARABIC_SHAPING arabic_shaping_table[] = {
75 {0x0600, 0x060F, JOINING_TYPE_NONE},
76 {0x0610, 0x061A, JOINING_TYPE_TRANSPARENT},
77 {0x061B, 0x061B, JOINING_TYPE_NONE},
78 {0x061C, 0x061C, JOINING_TYPE_TRANSPARENT},
79 {0x061B, 0x061F, JOINING_TYPE_NONE},
80 {0x0620, 0x0620, JOINING_TYPE_DUAL},
81 {0x0621, 0x0621, JOINING_TYPE_NONE},
82 {0x0622, 0x0625, JOINING_TYPE_RIGHT},
83 {0x0626, 0x0626, JOINING_TYPE_DUAL},
84 {0x0627, 0x0627, JOINING_TYPE_RIGHT},
85 {0x0628, 0x0628, JOINING_TYPE_DUAL},
86 {0x0629, 0x0629, JOINING_TYPE_RIGHT},
87 {0x062A, 0x062E, JOINING_TYPE_DUAL},
88 {0x062F, 0x0632, JOINING_TYPE_RIGHT},
89 {0x0633, 0x063F, JOINING_TYPE_DUAL},
90 {0x0640, 0x0640, JOINING_TYPE_CAUSING},
91 {0x0641, 0x0647, JOINING_TYPE_DUAL},
92 {0x0648, 0x0648, JOINING_TYPE_RIGHT},
93 {0x0649, 0x064A, JOINING_TYPE_DUAL},
94 {0x064B, 0x065F, JOINING_TYPE_TRANSPARENT},
95 {0x0660, 0x066D, JOINING_TYPE_NONE},
96 {0x066E, 0x066F, JOINING_TYPE_DUAL},
97 {0x0670, 0x0670, JOINING_TYPE_TRANSPARENT},
98 {0x0671, 0x0673, JOINING_TYPE_RIGHT},
99 {0x0674, 0x0674, JOINING_TYPE_NONE},
100 {0x0675, 0x0677, JOINING_TYPE_RIGHT},
101 {0x0678, 0x0687, JOINING_TYPE_DUAL},
102 {0x0688, 0x0699, JOINING_TYPE_RIGHT},
103 {0x069A, 0x06BF, JOINING_TYPE_DUAL},
104 {0x06C0, 0x06C0, JOINING_TYPE_RIGHT},
105 {0x06C1, 0x06C2, JOINING_TYPE_DUAL},
106 {0x06C3, 0x06CB, JOINING_TYPE_RIGHT},
107 {0x06CC, 0x06CC, JOINING_TYPE_DUAL},
108 {0x06CD, 0x06CD, JOINING_TYPE_RIGHT},
109 {0x06CE, 0x06CE, JOINING_TYPE_DUAL},
110 {0x06CF, 0x06CF, JOINING_TYPE_RIGHT},
111 {0x06D0, 0x06D1, JOINING_TYPE_DUAL},
112 {0x06D2, 0x06D3, JOINING_TYPE_RIGHT},
113 {0x06D4, 0x06D4, JOINING_TYPE_NONE},
114 {0x06D5, 0x06D5, JOINING_TYPE_RIGHT},
115 {0x06D6, 0x06DC, JOINING_TYPE_TRANSPARENT},
116 {0x06DD, 0x06DD, JOINING_TYPE_NONE},
117 {0x06DF, 0x06E4, JOINING_TYPE_TRANSPARENT},
118 {0x06E5, 0x06E6, JOINING_TYPE_NONE},
119 {0x06E7, 0x06E8, JOINING_TYPE_TRANSPARENT},
120 {0x06E9, 0x06E9, JOINING_TYPE_NONE},
121 {0x06EA, 0x06ED, JOINING_TYPE_TRANSPARENT},
122 {0x06EE, 0x06EF, JOINING_TYPE_RIGHT},
123 {0x06FA, 0x06FC, JOINING_TYPE_DUAL},
124 {0x06FF, 0x06FF, JOINING_TYPE_DUAL},
125 {0, 0, 0}
126 };
127
128 static ARABIC_FORM arabic_form_table_b[] = {
129 /* code, isolated, final, initial, medial */
130 {0x0621, 0xFE80, 0xFE80, 0xFE80, 0xFE80}, /* HAMZA 0x0621*/
131 {0x0622, 0xFE81, 0xFE82, 0xFE81, 0xFE82}, /* ALEF WITH MADDA ABOVE 0x622 */
132 {0x0623, 0xFE83, 0xFE84, 0xFE83, 0xFE84}, /* ALEF WITH HAMZA ABOVE 0x0623*/
133 {0x0624, 0xFE85, 0xFE86, 0xFE85, 0xFE86}, /* WAW WITH HAMZA ABOVE 0x0624 */
134 {0x0625, 0xFE87, 0xFE88, 0xFE87, 0xFE88}, /* ALEF WITH HAMZA BELOW 0x0625*/
135 {0x0626, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}, /* YEH WITH HAMZA ABOVE 0x0626*/
136 {0x0627, 0xFE8D, 0xFE8E, 0xFE8D, 0xFE8E}, /* ALEF 0x0627*/
137 {0x0628, 0xFE8F, 0xFE90, 0xFE91, 0xFE92}, /* BEH 0x0628*/
138 {0x0629, 0xFE93, 0xFE94, 0xFE93, 0xFE94}, /* TEH MARBUTA 0x0629*/
139 {0x062A, 0xFE95, 0xFE96, 0xFE97, 0xFE98}, /* TEH 0x062A*/
140 {0x062B, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}, /* THEH 0x062B*/
141 {0x062C, 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}, /* JEEM 0x062C*/
142 {0x062D, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}, /* HAH 0x062D*/
143 {0x062E, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}, /* KHAH 0x062E*/
144 {0x062F, 0xFEA9, 0xFEAA, 0xFEA9, 0xFEAA}, /* DAL 0x062F*/
145 {0x0630, 0xFEAB, 0xFEAC, 0xFEAB, 0xFEAC}, /* THAL0x0630 */
146 {0x0631, 0xFEAD, 0xFEAE, 0xFEAD, 0xFEAE}, /* RAA 0x0631*/
147 {0x0632, 0xFEAF, 0xFEB0, 0xFEAF, 0xFEB0}, /* ZAIN 0x0632*/
148 {0x0633, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}, /* SEEN 0x0633*/
149 {0x0634, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}, /* SHEEN 0x0634*/
150 {0x0635, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}, /* SAD 0x0635*/
151 {0x0636, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}, /* DAD 0x0636*/
152 {0x0637, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}, /* TAH 0x0637*/
153 {0x0638, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}, /* ZAH 0x0638*/
154 {0x0639, 0xFEC9, 0xFECA, 0xFECB, 0xFECC}, /* AIN 0x0639*/
155 {0x063A, 0xFECD, 0xFECE, 0xFECF, 0xFED0}, /* GHAIN 0x063A*/
156 {0x0641, 0xFED1, 0xFED2, 0xFED3, 0xFED4}, /* FAA 0x0641*/
157 {0x0642, 0xFED5, 0xFED6, 0xFED7, 0xFED8}, /* QAF 0x0642*/
158 {0x0643, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}, /* KAF 0x0643*/
159 {0x0644, 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}, /* LAM 0x0644*/
160 {0x0645, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}, /* MEEM 0x0645*/
161 {0x0646, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}, /* NOON 0x0646*/
162 {0x0647, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}, /* HEH 0x0647*/
163 {0x0648, 0xFEED, 0xFEEE, 0xFEED, 0xFEEE}, /* WAW 0x0648*/
164 {0x0649, 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9}, /* ALEF MAKSURA 0x0649*/
165 {0x064A, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}, /* YEH 0x064A*/
166 {0, 0, 0, 0, 0}
167 };
168
169 static ARABIC_FORM arabic_form_table_a[] = {
170 {0x0671, 0xFB50, 0xFB51, 0xFB50, 0xFB51}, /* Alef Wasla */
171 {0x0679, 0xFB66, 0xFB67, 0xFB68, 0xFB89}, /* Tteh */
172 {0x067A, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61}, /* Tteheh */
173 {0x067B, 0xFB52, 0xFB53, 0xFB54, 0xFB55}, /* Beeh */
174 {0x067E, 0xFB56, 0xFB57, 0xFB58, 0xFB59}, /* Peh */
175 {0x067F, 0xFB62, 0xFB63, 0xFB64, 0xFB65}, /* Teheh */
176 {0x0680, 0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}, /* Beheh */
177 {0x0683, 0xFB76, 0xFB77, 0xFB78, 0xFB79}, /* Nyeh */
178 {0x0684, 0xFB72, 0xFB73, 0xFB74, 0xFB75}, /* Dyeh */
179 {0x0686, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}, /* Tcheh */
180 {0x0688, 0xFB88, 0xFB89, 0xFB88, 0xFB89}, /* Ddal */
181 {0x0687, 0xFB7E, 0xFB7F, 0xFB80, 0xFB81}, /* Tcheheh */
182 {0x068D, 0xFB82, 0xFB83, 0xFB82, 0xFB83}, /* Ddahal */
183 {0x068E, 0xFB86, 0xFB87, 0xFB86, 0xFB87}, /* Dul */
184 {0x0691, 0xFB8C, 0xFB8D, 0xFB8C, 0xFB8D}, /* Rreh */
185 {0x0698, 0xFB8A, 0xFB8B, 0xFB8A, 0xFB8B}, /* Jeh */
186 {0x06A4, 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}, /* Veh */
187 {0x06A6, 0xFB6E, 0xFB6F, 0xFB70, 0xFB71}, /* Peheh */
188 {0x06A9, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91}, /* Keheh */
189 {0x06AD, 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6}, /* Ng */
190 {0x06AF, 0xFB92, 0xFB93, 0xFB94, 0xFB95}, /* Gaf */
191 {0x06B1, 0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D}, /* Ngoeh */
192 {0x06B3, 0xFB96, 0xFB97, 0xFB98, 0xFB99}, /* Gueh */
193 {0x06BA, 0xFB9E, 0xFB9F, 0xFB9E, 0xFB9F}, /* Noon Ghunna */
194 {0x06BB, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3}, /* Rnoon */
195 {0x06BE, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}, /* Heh Doachashmee */
196 {0x06C1, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9}, /* Heh Goal */
197 {0x06C5, 0xFBE0, 0xFBE1, 0xFBE0, 0xFBE1}, /* Kirghiz Oe */
198 {0x06C6, 0xFBD9, 0xFBDA, 0xFBD9, 0xFBDA}, /* Oe */
199 {0x06C7, 0xFBD7, 0xFBD8, 0xFBD7, 0xFBD8}, /* U */
200 {0x06C8, 0xFBDB, 0xFBDC, 0xFBDB, 0xFBDC}, /* Yu */
201 {0x06C9, 0xFBE2, 0xFBE3, 0xFBE2, 0xFBE3}, /* Kirghiz Yu */
202 {0x06CC, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}, /* Farsi Yeh */
203 {0x06D0, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}, /* E */
204 {0x06CB, 0xFBDE, 0xFBDF, 0xFBDE, 0xFBDF}, /* Ve */
205 {0x06D2, 0xFBAE, 0xFBAF, 0xFBAE, 0xFBAF}, /* Yeh Barree */
206 {0x06D3, 0xFBB0, 0xFBB1, 0xFBB0, 0xFBB1} /* Yeh Barree with Hamza Above */
207 };
208
209 static ARABIC_LIGATURE arabic_ligature_table[] =
210 {
211 /*alef, lam, (lam-alef) */
212 {0xFE82, 0xFEDF, 0xFEF5}, /* Arabic Ligature Lam with Alef with Madda Above Isolated Form */
213 {0xFE82, 0xFEE0, 0xFEF6}, /* Arabic Ligature Lam with Alef with Madda Above Final Form */
214 {0xFE84, 0xFEDF, 0xFEF7}, /* Arabic Ligature Lam with Alef with Hamza Above Isolated Form */
215 {0xFE84, 0xFEE0, 0xFEF8}, /* Arabic Ligature Lam with Alef with Hamza Above Final Form */
216 {0xFE88, 0xFEDF, 0xFEF9}, /* Arabic Ligature Lam with Alef with Hamza Below Isolated Form */
217 {0xFE88, 0xFEE0, 0xFEFA}, /* Arabic Ligature Lam with Alef with Hamza Below Final Form */
218 {0xFE8E, 0xFEDF, 0xFEFB}, /* Arabic Ligature Lam with Alef Isolated Form */
219 {0xFE8E, 0xFEE0, 0xFEFC}, /* Arabic Ligature Lam with Alef Final Form */
220 {0, 0, 0}
221 };
222
223 /**************************************************************************/
224 /* */
225 /* FUNCTION RELEASE */
226 /* */
227 /* _gx_utility_bidi_arabic_joining_type_get PORTABLE C */
228 /* 6.1 */
229 /* AUTHOR */
230 /* */
231 /* Kenneth Maxwell, Microsoft Corporation */
232 /* */
233 /* DESCRIPTION */
234 /* */
235 /* This function returns join type of sepecified unicode. */
236 /* */
237 /* INPUT */
238 /* */
239 /* code_point Code point */
240 /* */
241 /* OUTPUT */
242 /* */
243 /* joining type */
244 /* */
245 /* CALLS */
246 /* */
247 /* None */
248 /* */
249 /* CALLED BY */
250 /* */
251 /* _gx_utility_bidi_arabic_shaping */
252 /* */
253 /* RELEASE HISTORY */
254 /* */
255 /* DATE NAME DESCRIPTION */
256 /* */
257 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
258 /* */
259 /**************************************************************************/
_gx_utility_bidi_arabic_joining_type_get(ULONG code_point)260 static UINT _gx_utility_bidi_arabic_joining_type_get(ULONG code_point)
261 {
262 ARABIC_SHAPING *shaping = arabic_shaping_table;
263
264 if (code_point >= 0x0600 && code_point <= 0x06FF)
265 {
266 /* Arabic. */
267 while (shaping -> range_start)
268 {
269 if ((code_point >= shaping -> range_start) &&
270 (code_point <= shaping -> range_end))
271 {
272 return shaping -> joining_type;
273 }
274 shaping++;
275 }
276 }
277
278 return JOINING_TYPE_NONE;
279 }
280
281 /**************************************************************************/
282 /* */
283 /* FUNCTION RELEASE */
284 /* */
285 /* _gx_utility_bidi_arabic_form_get PORTABLE C */
286 /* 6.1 */
287 /* AUTHOR */
288 /* */
289 /* Kenneth Maxwell, Microsoft Corporation */
290 /* */
291 /* DESCRIPTION */
292 /* */
293 /* This function gets Arabic shape form. */
294 /* */
295 /* INPUT */
296 /* */
297 /* code_point Code point */
298 /* form_type Joining type */
299 /* */
300 /* OUTPUT */
301 /* */
302 /* status Completion status */
303 /* */
304 /* CALLS */
305 /* */
306 /* None */
307 /* */
308 /* CALLED BY */
309 /* */
310 /* _gx_utility_bidi_arabic_shaping */
311 /* */
312 /* RELEASE HISTORY */
313 /* */
314 /* DATE NAME DESCRIPTION */
315 /* */
316 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
317 /* */
318 /**************************************************************************/
_gx_utility_bidi_arabic_form_get(ULONG code_point,UINT form_type)319 static ULONG _gx_utility_bidi_arabic_form_get(ULONG code_point, UINT form_type)
320 {
321 ARABIC_FORM *entry = GX_NULL;
322
323 if ((code_point) >= 0x0621 && (code_point <= 0x064A))
324 {
325 entry = arabic_form_table_b;
326 }
327 else if (code_point >= 0x0671 && code_point <= 0x06D3)
328 {
329 entry = arabic_form_table_a;
330 }
331
332 if (entry)
333 {
334 while (entry -> code_point)
335 {
336 if (entry -> code_point == code_point)
337 {
338 switch (form_type)
339 {
340 case ARABIC_FORM_ISOLATED:
341 return entry -> isolated;
342
343 case ARABIC_FORM_INITIAL:
344 return entry -> initial;
345
346 case ARABIC_FORM_FINAL:
347 return entry -> final;
348
349 case ARABIC_FORM_MEDIAL:
350 return entry -> medial;
351 }
352 }
353
354 entry++;
355 }
356 }
357
358 return code_point;
359 }
360 /**************************************************************************/
361 /* */
362 /* FUNCTION RELEASE */
363 /* */
364 /* _gx_utility_bidi_arabic_ligature_get PORTABLE C */
365 /* 6.1 */
366 /* AUTHOR */
367 /* */
368 /* Kenneth Maxwell, Microsoft Corporation */
369 /* */
370 /* DESCRIPTION */
371 /* */
372 /* This function retrieves Arabic ligature. */
373 /* */
374 /* INPUT */
375 /* */
376 /* alef Code of Arabic letter alef */
377 /* lam Code of Arabic letter lam */
378 /* */
379 /* OUTPUT */
380 /* */
381 /* status Completion status */
382 /* */
383 /* CALLS */
384 /* */
385 /* None */
386 /* */
387 /* CALLED BY */
388 /* */
389 /* _gx_utility_bidi_arabic_shaping */
390 /* */
391 /* RELEASE HISTORY */
392 /* */
393 /* DATE NAME DESCRIPTION */
394 /* */
395 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
396 /* */
397 /**************************************************************************/
_gx_utility_bidi_arabic_ligature_get(ULONG alef,ULONG lam)398 static ULONG _gx_utility_bidi_arabic_ligature_get(ULONG alef, ULONG lam)
399 {
400 ARABIC_LIGATURE *entry = arabic_ligature_table;
401
402 while (entry -> ligature)
403 {
404 if (entry -> alef == alef && entry -> lam == lam)
405 {
406 return entry -> ligature;
407 }
408 entry++;
409 }
410
411 return 0;
412 }
413
414 /**************************************************************************/
415 /* */
416 /* FUNCTION RELEASE */
417 /* */
418 /* _gx_utility_bidi_right_joining_causing_test PORTABLE C */
419 /* 6.1 */
420 /* AUTHOR */
421 /* */
422 /* Kenneth Maxwell, Microsoft Corporation */
423 /* */
424 /* DESCRIPTION */
425 /* */
426 /* This function tests if a join type is right joining causing. */
427 /* */
428 /* INPUT */
429 /* */
430 /* joining_type Joining type */
431 /* */
432 /* OUTPUT */
433 /* */
434 /* status Completion status */
435 /* */
436 /* CALLS */
437 /* */
438 /* None */
439 /* */
440 /* CALLED BY */
441 /* */
442 /* _gx_utility_bidi_arabic_shaping */
443 /* */
444 /* RELEASE HISTORY */
445 /* */
446 /* DATE NAME DESCRIPTION */
447 /* */
448 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
449 /* */
450 /**************************************************************************/
_gx_utility_bidi_right_joining_causing_test(UINT joining_type)451 static GX_BOOL _gx_utility_bidi_right_joining_causing_test(UINT joining_type)
452 {
453 switch (joining_type)
454 {
455 case JOINING_TYPE_DUAL:
456 case JOINING_TYPE_LEFT:
457 case JOINING_TYPE_CAUSING:
458 return GX_TRUE;
459 }
460
461 return GX_FALSE;
462 }
463
464 /**************************************************************************/
465 /* */
466 /* FUNCTION RELEASE */
467 /* */
468 /* _gx_utility_bidi_left_joining_causing_test PORTABLE C */
469 /* 6.1 */
470 /* AUTHOR */
471 /* */
472 /* Kenneth Maxwell, Microsoft Corporation */
473 /* */
474 /* DESCRIPTION */
475 /* */
476 /* This function tests if a joing type is left joining causing. */
477 /* */
478 /* INPUT */
479 /* */
480 /* joinint_type Joining type */
481 /* */
482 /* OUTPUT */
483 /* */
484 /* status Completion status */
485 /* */
486 /* CALLS */
487 /* */
488 /* None */
489 /* */
490 /* CALLED BY */
491 /* */
492 /* _gx_utility_bidi_arabic_shaping */
493 /* */
494 /* RELEASE HISTORY */
495 /* */
496 /* DATE NAME DESCRIPTION */
497 /* */
498 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
499 /* */
500 /**************************************************************************/
_gx_utility_bidi_left_joining_causing_test(UINT joining_type)501 static GX_BOOL _gx_utility_bidi_left_joining_causing_test(UINT joining_type)
502 {
503 switch (joining_type)
504 {
505 case JOINING_TYPE_DUAL:
506 case JOINING_TYPE_RIGHT:
507 case JOINING_TYPE_CAUSING:
508 return GX_TRUE;
509 }
510
511 return GX_FALSE;
512 }
513
514 /**************************************************************************/
515 /* */
516 /* FUNCTION RELEASE */
517 /* */
518 /* _gx_utility_bidi_arabic_test PORTABLE C */
519 /* 6.1 */
520 /* AUTHOR */
521 /* */
522 /* Kenneth Maxwell, Microsoft Corporation */
523 /* */
524 /* DESCRIPTION */
525 /* */
526 /* This function tests is the specified strings contains Arabic. */
527 /* */
528 /* INPUT */
529 /* */
530 /* context Bidi information control block*/
531 /* */
532 /* OUTPUT */
533 /* */
534 /* status Completion status */
535 /* */
536 /* CALLS */
537 /* */
538 /* None */
539 /* */
540 /* CALLED BY */
541 /* */
542 /* _gx_utility_bidi_arabic_shaping */
543 /* */
544 /* RELEASE HISTORY */
545 /* */
546 /* DATE NAME DESCRIPTION */
547 /* */
548 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
549 /* */
550 /**************************************************************************/
_gx_utility_bidi_arabic_test(GX_BIDI_CONTEXT * context)551 static GX_BOOL _gx_utility_bidi_arabic_test(GX_BIDI_CONTEXT *context)
552 {
553 GX_BIDI_UNIT *unit = context -> gx_bidi_context_unit_list;
554 INT index;
555
556 for (index = 0; index < context -> gx_bidi_context_unit_count; index++)
557 {
558 if ((unit -> gx_bidi_unit_code >= 0x0600) && (unit -> gx_bidi_unit_code <= 0x06FF))
559 {
560 return GX_TRUE;
561 }
562
563 unit++;
564 }
565
566 return GX_FALSE;
567 }
568
569 /**************************************************************************/
570 /* */
571 /* FUNCTION RELEASE */
572 /* */
573 /* _gx_utility_bidi_arabic_shaping PORTABLE C */
574 /* 6.1 */
575 /* AUTHOR */
576 /* */
577 /* Kenneth Maxwell, Microsoft Corporation */
578 /* */
579 /* DESCRIPTION */
580 /* */
581 /* This function shapes Arabic glyphs according to logical order. */
582 /* */
583 /* INPUT */
584 /* */
585 /* context Bidi information control block*/
586 /* */
587 /* OUTPUT */
588 /* */
589 /* status Completion status */
590 /* */
591 /* CALLS */
592 /* */
593 /* None */
594 /* */
595 /* CALLED BY */
596 /* */
597 /* _gx_utility_bidi_paragraph_reorder */
598 /* */
599 /* RELEASE HISTORY */
600 /* */
601 /* DATE NAME DESCRIPTION */
602 /* */
603 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
604 /* */
605 /**************************************************************************/
_gx_utility_bidi_arabic_shaping(GX_BIDI_CONTEXT * context)606 UINT _gx_utility_bidi_arabic_shaping(GX_BIDI_CONTEXT *context)
607 {
608 ARABIC_UNIT *arabic_unit;
609 ARABIC_UNIT *pre_unit;
610 ARABIC_UNIT *unit;
611 ARABIC_UNIT *follow_unit;
612 ULONG ligature;
613 INT index;
614 GX_BIDI_UNIT *bidi_unit;
615 GX_BIDI_UNIT *pre_bidi_unit;
616 GX_UBYTE utf8[6];
617 UINT glyph_len;
618 INT increment;
619 UINT form_type = 0;
620 INT buffer_size;
621
622 /* Test Arabic glyph. */
623 if (_gx_utility_bidi_arabic_test(context) == GX_FALSE)
624 {
625 /* Nothing to change. */
626 return GX_SUCCESS;
627 }
628
629 buffer_size = (context -> gx_bidi_context_unit_count + 1) * (INT)sizeof(ARABIC_UNIT);
630
631 /* Allocate memory for Arabic shaping. */
632 arabic_unit = (ARABIC_UNIT *)_gx_system_memory_allocator((UINT)buffer_size);
633
634 if (arabic_unit == GX_NULL)
635 {
636 return GX_SYSTEM_MEMORY_ERROR;
637 }
638
639 /* Initiate Arabic shaping information list. */
640 for (index = 0; index < context -> gx_bidi_context_unit_count; index++)
641 {
642 arabic_unit[index].code_point = context -> gx_bidi_context_unit_list[index].gx_bidi_unit_code;
643 arabic_unit[index].shape_form = arabic_unit[index].code_point;
644 arabic_unit[index].joining_type = _gx_utility_bidi_arabic_joining_type_get(arabic_unit[index].code_point);
645 }
646
647 arabic_unit[index].code_point = 0;
648 arabic_unit[index].joining_type = 0;
649
650 pre_unit = NULL;
651 unit = arabic_unit;
652 bidi_unit = context -> gx_bidi_context_unit_list;
653
654 /* Start shaping. */
655 while (unit -> code_point)
656 {
657 increment = 1;
658
659 if (unit -> joining_type == JOINING_TYPE_TRANSPARENT)
660 {
661 /* Rule 1: Transparent characters do not affect the joining behavior of base characters. */
662 unit++;
663 }
664 else
665 {
666 follow_unit = unit + 1;
667
668 /* Find next non-transparent character. */
669 while (follow_unit -> code_point && follow_unit -> joining_type == JOINING_TYPE_TRANSPARENT)
670 {
671 increment++;
672 follow_unit++;
673 }
674
675 if (unit -> joining_type == JOINING_TYPE_RIGHT && pre_unit && _gx_utility_bidi_right_joining_causing_test(pre_unit -> joining_type))
676 {
677 /* Rule 2: a right-joining character x that has a right joining-causing character on the right(preceding) will
678 adopt the form x-right. */
679 form_type = ARABIC_FORM_FINAL;
680 }
681 else if (unit -> joining_type == JOINING_TYPE_LEFT && _gx_utility_bidi_left_joining_causing_test(follow_unit -> joining_type))
682 {
683 /* Rule 3: a left-joining character x that has a left joining-causing character on the left(following) will
684 adopt the form x-left. */
685 form_type = ARABIC_FORM_INITIAL;
686 }
687 else if (unit -> joining_type == JOINING_TYPE_DUAL &&
688 pre_unit && _gx_utility_bidi_right_joining_causing_test(pre_unit -> joining_type) &&
689 _gx_utility_bidi_left_joining_causing_test(follow_unit -> joining_type))
690 {
691 /* Rule 4: a dual-joining character x that has a right joining-causing character on the right(preceding) and
692 a left join-causing character on the left(following) will adopt the form x-medial. */
693 form_type = ARABIC_FORM_MEDIAL;
694 }
695 else if (unit -> joining_type == JOINING_TYPE_DUAL &&
696 pre_unit && _gx_utility_bidi_right_joining_causing_test(pre_unit -> joining_type) &&
697 !_gx_utility_bidi_left_joining_causing_test(follow_unit -> joining_type))
698 {
699 /* Rule 5: a dual-joining character x that has a right join-causing character on the right(preceding) and
700 no left join-causing character on the left(following) will adopt the form x-right. */
701 form_type = ARABIC_FORM_FINAL;
702 }
703 else if (unit -> joining_type == JOINING_TYPE_DUAL &&
704 _gx_utility_bidi_left_joining_causing_test(follow_unit -> joining_type) &&
705 ((pre_unit == GX_NULL) || !_gx_utility_bidi_right_joining_causing_test(pre_unit -> joining_type)))
706 {
707 /* Rule 6: a dual-joining character x that has left joining-causing character on the left(following) and
708 no right join-causing character on the right(preceding) will adopt the form x-left. */
709 form_type = ARABIC_FORM_INITIAL;
710 }
711
712 if (form_type)
713 {
714 unit -> shape_form = _gx_utility_bidi_arabic_form_get(unit -> code_point, form_type);
715 form_type = 0;
716
717 if (pre_unit)
718 {
719 /* Any sequence with alef-right on the left(following) and lam-medial on the right(preceding) will form
720 the ligature (lam-alef)-right. */
721 ligature = _gx_utility_bidi_arabic_ligature_get(unit -> shape_form, pre_unit -> shape_form);
722 if (ligature)
723 {
724 pre_unit -> shape_form = ligature;
725 pre_bidi_unit -> gx_bidi_unit_code = ligature;
726 unit -> shape_form = 0;
727 }
728 }
729
730 bidi_unit -> gx_bidi_unit_code = unit -> shape_form;
731 }
732
733 pre_bidi_unit = bidi_unit;
734 pre_unit = unit;
735 unit = follow_unit;
736 }
737
738 bidi_unit += increment;
739 }
740
741 /* Calculate total utf8 size for shaped glyphs. */
742 context -> gx_bidi_context_reordered_utf8_size = 0;
743 bidi_unit = context -> gx_bidi_context_unit_list;
744 for (index = 0; index < context -> gx_bidi_context_unit_count; index++)
745 {
746 if (bidi_unit -> gx_bidi_unit_code)
747 {
748 _gx_utility_unicode_to_utf8(bidi_unit -> gx_bidi_unit_code, utf8, &glyph_len);
749 context -> gx_bidi_context_reordered_utf8_size += glyph_len;
750 }
751
752 bidi_unit++;
753 }
754
755 _gx_system_memory_free(arabic_unit);
756
757 return GX_SUCCESS;
758 }
759 #endif
760 #endif
761
762