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
21 #define GX_SOURCE_CODE
22
23 /* Include necessary system files. */
24
25 #include "gx_api.h"
26 #include "gx_system.h"
27 #include "gx_utility.h"
28
29 /* Define thai glyph class types. */
30 #ifdef GX_THAI_GLYPH_SHAPING_SUPPORT
31 #define GX_THAI_GLYPH_CLASS_BASE 0x01
32 #define GX_THAI_GLYPH_CLASS_BASE_DESC 0x02
33 #define GX_THAI_GLYPH_CLASS_BASE_ASC 0x03
34 #define GX_THAI_GLYPH_CLASS_TOP 0x04
35 #define GX_THAI_GLYPH_CLASS_LOWER 0x05
36 #define GX_THAI_GLYPH_CLASS_UPPER 0x06
37 #endif
38
39 /**************************************************************************/
40 /* */
41 /* FUNCTION RELEASE */
42 /* */
43 /* _gx_utility_thai_utf8_to_unicode PORTABLE C */
44 /* 6.1 */
45 /* AUTHOR */
46 /* */
47 /* Kenneth Maxwell, Microsoft Corporation */
48 /* */
49 /* DESCRIPTION */
50 /* */
51 /* This function converts utf8 string to unicode and split sara am to */
52 /* nikhahit(0x0e4d) and sara aa(0x0e32). */
53 /* */
54 /* INPUT */
55 /* */
56 /* string Pointer to string */
57 /* font Font for text drawing */
58 /* textmap Pointer to pixemap structure */
59 /* */
60 /* OUTPUT */
61 /* */
62 /* status Completion status */
63 /* */
64 /* CALLS */
65 /* */
66 /* _gx_utility_utf8_string_character_get Retrieve code value of utf8 */
67 /* string */
68 /* _gx_system_memory_allocator Application defined memory */
69 /* allocator. */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* _gx_utility_thai_glyph_shaping */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
80 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* */
83 /**************************************************************************/
84 #ifdef GX_THAI_GLYPH_SHAPING_SUPPORT
_gx_utility_thai_utf8_to_unicode(GX_CONST GX_STRING * string,GX_CHAR_CODE ** returned_code_list,UINT * returned_code_count)85 static UINT _gx_utility_thai_utf8_to_unicode(GX_CONST GX_STRING *string, GX_CHAR_CODE **returned_code_list, UINT *returned_code_count)
86 {
87 GX_CHAR_CODE code_point;
88 UINT ret;
89 GX_CHAR_CODE *code_list;
90 UINT code_count = 0;
91 GX_STRING string_copy = *string;
92 GX_BOOL is_thai_string = GX_FALSE;
93
94 while (string_copy.gx_string_length > 0)
95 {
96 ret = _gx_utility_utf8_string_character_get(&string_copy, &code_point, GX_NULL);
97 if ((ret != GX_SUCCESS) || (code_point == 0))
98 {
99 return GX_FAILURE;
100 }
101
102 code_count++;
103
104 if ((!is_thai_string) && (code_point >= 0xe00) && (code_point <= 0xe7f))
105 {
106 is_thai_string = GX_TRUE;
107 }
108
109 if (code_point == 0xe33)
110 {
111 /* The vowel sara am will be split into the character nikhahit and sara aa if it is
112 appended to a consonant. */
113 code_count++;
114 }
115 }
116
117 if (!is_thai_string)
118 {
119 return GX_NO_CHANGE;
120 }
121
122 code_list = (GX_CHAR_CODE *)_gx_system_memory_allocator(sizeof(GX_CHAR_CODE) * code_count);
123 if (!code_list)
124 {
125 return GX_SYSTEM_MEMORY_ERROR;
126 }
127
128 string_copy = *string;
129 code_count = 0;
130
131 while (string_copy.gx_string_length > 0)
132 {
133 _gx_utility_utf8_string_character_get(&string_copy, &code_point, GX_NULL);
134
135 if (code_point == 0xe33)
136 {
137 code_list[code_count++] = 0xe4d;
138 code_list[code_count++] = 0xe32;
139 }
140 else
141 {
142 code_list[code_count++] = code_point;
143 }
144 }
145
146 *returned_code_list = code_list;
147 *returned_code_count = code_count;
148
149 return GX_SUCCESS;
150 }
151 #endif
152
153 /**************************************************************************/
154 /* */
155 /* FUNCTION RELEASE */
156 /* */
157 /* _gx_utility_thai_glyph_class_type_get PORTABLE C */
158 /* 6.1 */
159 /* AUTHOR */
160 /* */
161 /* Kenneth Maxwell, Microsoft Corporation */
162 /* */
163 /* DESCRIPTION */
164 /* */
165 /* This function retrieves thai glyph class for specified unicode. */
166 /* */
167 /* INPUT */
168 /* */
169 /* code Specified unicode */
170 /* return_type Retrieved thai glyph class */
171 /* */
172 /* OUTPUT */
173 /* */
174 /* status Completion status */
175 /* */
176 /* CALLS */
177 /* */
178 /* None */
179 /* */
180 /* CALLED BY */
181 /* */
182 /* _gx_utility_thai_glyph_shaping */
183 /* */
184 /* RELEASE HISTORY */
185 /* */
186 /* DATE NAME DESCRIPTION */
187 /* */
188 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
189 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
190 /* resulting in version 6.1 */
191 /* */
192 /**************************************************************************/
193 #ifdef GX_THAI_GLYPH_SHAPING_SUPPORT
_gx_utility_thai_glyph_class_type_get(ULONG code,GX_UBYTE * return_type)194 static UINT _gx_utility_thai_glyph_class_type_get(ULONG code, GX_UBYTE *return_type)
195 {
196 GX_UBYTE type;
197
198 if (((code >= 0xe01) && (code <= 0xe2f)) ||
199 (code == 0xe30) ||
200 (code == 0xe40) ||
201 (code == 0xe41))
202 {
203 if ((code == 0xe0e) || (code == 0xe0f))
204 {
205 type = GX_THAI_GLYPH_CLASS_BASE_DESC;
206 }
207 else if ((code == 0xe1b) || (code == 0xe1d) || (code == 0xe1f) || (code == 0xe2c))
208 {
209 type = GX_THAI_GLYPH_CLASS_BASE_ASC;
210 }
211 else
212 {
213 type = GX_THAI_GLYPH_CLASS_BASE;
214 }
215 }
216 else if ((code >= 0xe48) && (code <= 0xe4c))
217 {
218 type = GX_THAI_GLYPH_CLASS_TOP;
219 }
220 else if ((code >= 0xe38) && (code <= 0xe3a))
221 {
222 type = GX_THAI_GLYPH_CLASS_LOWER;
223 }
224 else if ((code == 0xe31) || ((code >= 0xe34) && (code <= 0xe37)) ||
225 (code == 0xe47) || (code == 0xe4d))
226 {
227 type = GX_THAI_GLYPH_CLASS_UPPER;
228 }
229 else
230 {
231 type = 0;
232 }
233
234 *return_type = type;
235
236 return GX_SUCCESS;
237 }
238 #endif
239
240 /**************************************************************************/
241 /* */
242 /* FUNCTION RELEASE */
243 /* */
244 /* _gx_utility_thai_glyph_shaping PORTABLE C */
245 /* 6.1 */
246 /* AUTHOR */
247 /* */
248 /* Kenneth Maxwell, Microsoft Corporation */
249 /* */
250 /* DESCRIPTION */
251 /* */
252 /* This function adjusts thai glyph position by substitution */
253 /* technique with extra glyph sets that defined in Private Use Area. */
254 /* */
255 /* INPUT */
256 /* */
257 /* string Thai string for shaping */
258 /* count String size in bytes */
259 /* returned_code_list Adjusted unicode list */
260 /* returned_code_count Adjusted unicode count */
261 /* */
262 /* OUTPUT */
263 /* */
264 /* status Completion status */
265 /* */
266 /* CALLS */
267 /* */
268 /* _gx_utility_thai_utf8_to_unicode Convert utf8 string to unicode*/
269 /* _gx_utility_thai_glyph_class_type_get Retrieve thai glyph class */
270 /* */
271 /* CALLED BY */
272 /* */
273 /* Application Software */
274 /* */
275 /* RELEASE HISTORY */
276 /* */
277 /* DATE NAME DESCRIPTION */
278 /* */
279 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
280 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
281 /* resulting in version 6.1 */
282 /* */
283 /**************************************************************************/
284 #ifdef GX_THAI_GLYPH_SHAPING_SUPPORT
_gx_utility_thai_glyph_shaping(GX_CONST GX_STRING * string,GX_CHAR_CODE ** returned_code_list,UINT * returned_code_count)285 UINT _gx_utility_thai_glyph_shaping(GX_CONST GX_STRING *string, GX_CHAR_CODE **returned_code_list, UINT *returned_code_count)
286 {
287 /****************************************************/
288 /* Extra Glyph Sets */
289 /* F700: uni0E10.descless (base.descless) */
290 /* F701~04: uni0E34~37.left (upper.left) */
291 /* F705~09: uni0E48~4C.lowleft (top.lowleft) */
292 /* F70A~0E: uni0E48~4C.low (top.low) */
293 /* F70F: uni0E0D.descless (base.descless) */
294 /* F710~12: uni0E31,4D,47.left (upper.left) */
295 /* F713~17: uni0E48~4C.left (top.left) */
296 /* F718~1A: uni0E38~3A.low (lower.low) */
297 /****************************************************/
298 GX_CHAR_CODE *code_list;
299 UINT code_count;
300 UINT status;
301 UINT index;
302 GX_UBYTE type;
303 GX_UBYTE pp_type = 0;
304 GX_UBYTE p_type = 0;
305 GX_UBYTE f_type;
306 GX_UBYTE t;
307 GX_BOOL f_nikhahit;
308
309 /* Convert utf8 string to unicode string. */
310 status = _gx_utility_thai_utf8_to_unicode(string, &code_list, &code_count);
311
312 if (status == GX_SUCCESS)
313 {
314 _gx_utility_thai_glyph_class_type_get(code_list[0], &type);
315
316 for (index = 0; index < code_count; index++)
317 {
318 if (index < code_count - 1)
319 {
320 _gx_utility_thai_glyph_class_type_get(code_list[index + 1], &f_type);
321 }
322 else
323 {
324 f_type = 0;
325 }
326
327 if ((type == GX_THAI_GLYPH_CLASS_TOP) && index)
328 {
329 /* base + top --> base + top.low. */
330 /* base + lower + top -> base + lower + top.low. */
331 /* base.asc + top --> base.asc + top.lowleft. */
332 /* base.asc + lower + top --> base.asc + lower + top.lowleft. */
333 if (p_type == GX_THAI_GLYPH_CLASS_LOWER)
334 {
335 t = pp_type;
336 }
337 else
338 {
339 t = p_type;
340 }
341
342 if ((t == GX_THAI_GLYPH_CLASS_BASE) ||
343 (t == GX_THAI_GLYPH_CLASS_BASE_ASC) ||
344 (t == GX_THAI_GLYPH_CLASS_BASE_DESC))
345 {
346 if ((index < code_count - 1) && (code_list[index + 1] == 0xe4d))
347 {
348 f_nikhahit = GX_TRUE;
349 }
350 else
351 {
352 f_nikhahit = GX_FALSE;
353 }
354
355 if (t == GX_THAI_GLYPH_CLASS_BASE_ASC)
356 {
357 if (f_nikhahit)
358 {
359 /* base.asc + top + sara am --> base.asc + nikhahit.left + top.left + sara aa. */
360 code_list[index + 1] = (GX_CHAR_CODE)(code_list[index] - 0xe48 + 0xf713);
361 code_list[index] = 0xf711;
362 code_list[index + 2] = 0xe32;
363 index += 2;
364 pp_type = 0;
365 p_type = 0;
366 type = 0;
367 continue;
368 }
369 else
370 {
371 /* base.asc + top --> base.asc + top.lowerleft. */
372 code_list[index] = (GX_CHAR_CODE)(code_list[index] - 0xe48 + 0xf705);
373 }
374 }
375 else
376 {
377 if (!f_nikhahit)
378 {
379 /* base + top --> base + top.low */
380 code_list[index] = (GX_CHAR_CODE)(code_list[index] - 0xe48 + 0xf70a);
381 }
382 }
383 }
384
385 if ((pp_type == GX_THAI_GLYPH_CLASS_BASE_ASC) && (p_type == GX_THAI_GLYPH_CLASS_UPPER))
386 {
387 /* base.asc + upper + top --> base.asc + upper + top.left. */
388 code_list[index] = (GX_CHAR_CODE)(code_list[index] - 0xe48 + 0xf713);
389 }
390 }
391 else if ((p_type == GX_THAI_GLYPH_CLASS_BASE_ASC) && (type == GX_THAI_GLYPH_CLASS_UPPER))
392 {
393 /* base.asc + upper --> base.asc + upper.left. */
394 switch (code_list[index])
395 {
396 case 0xe31:
397 code_list[index] = 0xf710;
398 break;
399 case 0xe34:
400 case 0xe35:
401 case 0xe36:
402 case 0xe37:
403 code_list[index] = (GX_CHAR_CODE)(code_list[index] - 0xe34 + 0xf701);
404 break;
405 case 0xe4d:
406 code_list[index] = 0xf711;
407 break;
408 case 0xe47:
409 code_list[index] = 0xf712;
410 break;
411 }
412 }
413 else if ((p_type == GX_THAI_GLYPH_CLASS_BASE_DESC) && (type == GX_THAI_GLYPH_CLASS_LOWER))
414 {
415 /* base.desc + lower --> base.desc + lower.low. */
416 code_list[index] = (GX_CHAR_CODE)(code_list[index] - 0xe38 + 0xf718);
417 }
418 else if ((code_list[index] == 0xe0d) && (f_type == GX_THAI_GLYPH_CLASS_LOWER))
419 {
420 /* yong ying drop its lower part if combined with a lower vowel. */
421 /* base.desclike + lower --> base.descless. */
422 code_list[index] = 0xf70f;
423 }
424 else if ((code_list[index] == 0xe10) && (f_type == GX_THAI_GLYPH_CLASS_LOWER))
425 {
426 /* tho than drop its lower part if combined with a lower vowel. */
427 /* base.desclike + lower --- base.descless. */
428 code_list[index] = 0xf700;
429 }
430
431 pp_type = p_type;
432 p_type = type;
433 type = f_type;
434 }
435
436 *returned_code_list = code_list;
437 *returned_code_count = code_count;
438 }
439 else
440 {
441 *returned_code_list = GX_NULL;
442 *returned_code_count = 0;
443 }
444
445 return status;
446 }
447 #endif
448
449