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