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 /**   Canvas Management (Canvas)                                          */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_utility.h"
29 #include "gx_canvas.h"
30 
31 #if defined(GX_FONT_KERNING_SUPPORT)
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _gx_canvas_kerning_glyphs_draw                      PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Kenneth Maxwell, Microsoft Corporation                              */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function prepares to draw text.                                */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    context                               Drawing context               */
49 /*    font                                  Font used by the string       */
50 /*    draw_position                         Coord of draw position        */
51 /*    string                                Pointer to string which need  */
52 /*                                            to draw                     */
53 /*    length                                Number of string about to draw*/
54 /*    view                                  Pointer to view size          */
55 /*    draw_glyph                            Callback pointer to display   */
56 /*                                            driver text draw function   */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*    _gx_utility_utf8_string_character_get                               */
64 /*                                    Get characters of this string       */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    _gx_canvas_glyph_draw                                               */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
75 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*                                                                        */
78 /**************************************************************************/
_gx_canvas_kerning_glyphs_draw(GX_DRAW_CONTEXT * context,GX_FONT * font,GX_POINT * draw_position,GX_CONST GX_STRING * string,GX_RECTANGLE * view,VOID (* draw_glyph)(GX_DRAW_CONTEXT *,GX_RECTANGLE *,GX_POINT *,GX_CONST GX_GLYPH *))79 static VOID _gx_canvas_kerning_glyphs_draw(GX_DRAW_CONTEXT *context, GX_FONT *font, GX_POINT *draw_position, GX_CONST GX_STRING *string, GX_RECTANGLE *view,
80                                            VOID (*draw_glyph)(GX_DRAW_CONTEXT *, GX_RECTANGLE *, GX_POINT *, GX_CONST GX_GLYPH *))
81 {
82 GX_CONST GX_KERNING_GLYPH *glyph;
83 GX_CHAR_CODE               char_val;
84 GX_VALUE                   x_offset;
85 GX_VALUE                   y_offset;
86 GX_VALUE                   xstart;
87 GX_VALUE                   ystart;
88 GX_POINT                   map_offset;
89 GX_RECTANGLE               draw_area;
90 GX_CONST GX_FONT          *font_link;
91 
92 /* Used for kerning glyph. */
93 GX_CHAR_CODE       pre_char_val = 0;
94 GX_BYTE            kerning_offset = 0;
95 GX_CONST GX_UBYTE *kerning_table;
96 INT                kerning_counts;
97 INT                index;
98 GX_UBYTE          *left_glyph_ptr;
99 GX_STRING          string_copy;
100 
101 #if defined(GX_UTF8_SUPPORT)
102 UINT ret;
103 #endif /* GX_UTF8_SUPPORT */
104 
105     /* Setup local variables.  */
106 
107     xstart = draw_position -> gx_point_x;
108     ystart = draw_position -> gx_point_y;
109     string_copy = *string;
110 
111     /* for each character in the string */
112     do
113     {
114 #ifdef GX_UTF8_SUPPORT
115         ret = _gx_utility_utf8_string_character_get(&string_copy, &char_val, GX_NULL);
116 
117         if ((ret != GX_SUCCESS) || (char_val == 0))
118 #else
119         char_val = (GX_CHAR_CODE)(*string_copy.gx_string_ptr++);
120         string_copy.gx_string_length--;
121 
122         if (char_val == 0)
123 #endif /* GX_UTF8_SUPPORT */
124         {
125             break;
126         }
127 
128         font_link = font;
129         while (font_link)
130         {
131             if (char_val >= font_link -> gx_font_first_glyph &&
132                 char_val <= font_link -> gx_font_last_glyph)
133             {
134                 break;
135             }
136             font_link = font_link -> gx_font_next_page;
137         }
138 
139         if (font_link)
140         {
141             char_val = (GX_CHAR_CODE)(char_val - font_link -> gx_font_first_glyph);
142 
143             glyph = &((GX_CONST GX_KERNING_GLYPH *)font_link -> gx_font_glyphs.gx_font_kerning_glyphs)[char_val];
144             kerning_table = ((GX_KERNING_GLYPH *)glyph) -> gx_kerning_table;
145             if (kerning_table && (pre_char_val != 0))
146             {
147                 /* Search the kerning table for the kerning value. */
148                 kerning_counts = *kerning_table;
149                 left_glyph_ptr = (GX_UBYTE *)(kerning_table + 1);
150 
151                 for (index = 0; index < kerning_counts; index++)
152                 {
153                     if ((*left_glyph_ptr) == (pre_char_val + font_link -> gx_font_first_glyph))
154                     {
155                         kerning_offset = (GX_CHAR)(*(left_glyph_ptr + 1));
156                         break;
157                     }
158                     left_glyph_ptr += 2;
159                 }
160             }
161 
162             if (glyph -> gx_glyph_map)
163             {
164                 x_offset = (GX_VALUE)(xstart + glyph -> gx_glyph_leading);
165                 x_offset = (GX_VALUE)(x_offset + kerning_offset);
166                 y_offset = (GX_VALUE)(ystart + font_link -> gx_font_baseline - glyph -> gx_glyph_ascent);
167 
168                 draw_area.gx_rectangle_left = x_offset;
169                 draw_area.gx_rectangle_top = y_offset;
170                 draw_area.gx_rectangle_right = (GX_VALUE)(draw_area.gx_rectangle_left + glyph -> gx_glyph_width - 1);
171                 draw_area.gx_rectangle_bottom = (GX_VALUE)(draw_area.gx_rectangle_top + glyph -> gx_glyph_height - 1);
172 
173                 if (draw_area.gx_rectangle_bottom >= view -> gx_rectangle_top &&
174                     draw_area.gx_rectangle_top <= view -> gx_rectangle_bottom &&
175                     draw_area.gx_rectangle_right >= view -> gx_rectangle_left &&
176                     draw_area.gx_rectangle_left <= view -> gx_rectangle_right)
177                 {
178                     map_offset.gx_point_x = 0;
179                     map_offset.gx_point_y = 0;
180                     /* Calculate the y_start value, which is the offset into the row of
181                        the glyph where we start to the draw. */
182                     if (draw_area.gx_rectangle_top < view -> gx_rectangle_top)
183                     {
184                         map_offset.gx_point_y = (GX_VALUE)(view -> gx_rectangle_top - draw_area.gx_rectangle_top);
185                         draw_area.gx_rectangle_top = view -> gx_rectangle_top;
186                     }
187 
188                     if (draw_area.gx_rectangle_left < view -> gx_rectangle_left)
189                     {
190                         map_offset.gx_point_x = (GX_VALUE)(view -> gx_rectangle_left - x_offset);
191                         draw_area.gx_rectangle_left = view -> gx_rectangle_left;
192                     }
193 
194                     if (draw_area.gx_rectangle_bottom > view -> gx_rectangle_bottom)
195                     {
196                         draw_area.gx_rectangle_bottom = view -> gx_rectangle_bottom;
197                     }
198                     if (draw_area.gx_rectangle_right > view -> gx_rectangle_right)
199                     {
200                         draw_area.gx_rectangle_right = view -> gx_rectangle_right;
201                     }
202 
203                     draw_glyph(context, &draw_area, &map_offset, (const GX_GLYPH *)glyph);
204                 }
205             }
206             xstart = (GX_VALUE)(xstart + glyph -> gx_glyph_advance);
207             xstart = (GX_VALUE)(xstart + kerning_offset);
208         }
209 
210         pre_char_val = char_val;
211         kerning_offset = 0;
212     } while (string_copy.gx_string_length > 0);
213 }
214 #endif
215 
216 
217 /**************************************************************************/
218 /*                                                                        */
219 /*  FUNCTION                                               RELEASE        */
220 /*                                                                        */
221 /*    _gx_canvas_compressed_glyphs_draw                   PORTABLE C      */
222 /*                                                           6.1          */
223 /*  AUTHOR                                                                */
224 /*                                                                        */
225 /*    Kenneth Maxwell, Microsoft Corporation                              */
226 /*                                                                        */
227 /*  DESCRIPTION                                                           */
228 /*                                                                        */
229 /*    This function prepares to draw text.                                */
230 /*                                                                        */
231 /*  INPUT                                                                 */
232 /*                                                                        */
233 /*    context                               Drawing context               */
234 /*    font                                  Font used by the string       */
235 /*    draw_position                         Coord of draw position        */
236 /*    string                                Pointer to string which need  */
237 /*                                            to draw                     */
238 /*    length                                Number of string about to draw*/
239 /*    view                                  Pointer to view size          */
240 /*    draw_glyph                            Callback pointer to display   */
241 /*                                            driver text draw function   */
242 /*                                                                        */
243 /*  OUTPUT                                                                */
244 /*                                                                        */
245 /*                                                                        */
246 /*  CALLS                                                                 */
247 /*                                                                        */
248 /*    _gx_utility_utf8_string_character_get                               */
249 /*                                    Get characters of this string       */
250 /*                                                                        */
251 /*  CALLED BY                                                             */
252 /*                                                                        */
253 /*    _gx_canvas_glyph_draw                                               */
254 /*                                                                        */
255 /*  RELEASE HISTORY                                                       */
256 /*                                                                        */
257 /*    DATE              NAME                      DESCRIPTION             */
258 /*                                                                        */
259 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
260 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
261 /*                                            resulting in version 6.1    */
262 /*                                                                        */
263 /**************************************************************************/
_gx_canvas_compressed_glyphs_draw(GX_DRAW_CONTEXT * context,GX_FONT * font,GX_POINT * draw_position,GX_CONST GX_STRING * string,GX_RECTANGLE * view,VOID (* draw_glyph)(GX_DRAW_CONTEXT *,GX_RECTANGLE *,GX_POINT *,GX_CONST GX_GLYPH *))264 static VOID _gx_canvas_compressed_glyphs_draw(GX_DRAW_CONTEXT *context, GX_FONT *font, GX_POINT *draw_position, GX_CONST GX_STRING *string, GX_RECTANGLE *view,
265                                               VOID (*draw_glyph)(GX_DRAW_CONTEXT *, GX_RECTANGLE *, GX_POINT *, GX_CONST GX_GLYPH *))
266 {
267 GX_CONST GX_COMPRESSED_GLYPH *glyph;
268 GX_CHAR_CODE                  char_val;
269 GX_VALUE                      x_offset;
270 GX_VALUE                      y_offset;
271 GX_VALUE                      xstart;
272 GX_VALUE                      ystart;
273 GX_POINT                      map_offset;
274 GX_RECTANGLE                  draw_area;
275 GX_CONST GX_FONT             *font_link;
276 GX_STRING                     string_copy;
277 
278 #ifdef GX_UTF8_SUPPORT
279 UINT ret;
280 
281 #ifdef GX_THAI_GLYPH_SHAPING_SUPPORT
282 GX_CHAR_CODE *code_list = GX_NULL;
283 UINT          code_count;
284 UINT          index = 0;
285     if (_gx_system_text_render_style & GX_TEXT_RENDER_THAI_GLYPH_SHAPING)
286     {
287         ret = _gx_utility_thai_glyph_shaping(string, &code_list, &code_count);
288     }
289 #endif
290 
291 #endif /* GX_UTF8_SUPPORT */
292 
293     /* Setup local variables.  */
294     xstart = draw_position -> gx_point_x;
295     ystart = draw_position -> gx_point_y;
296     string_copy = *string;
297 
298     /* for each character in the string */
299     do
300     {
301 #ifdef GX_UTF8_SUPPORT
302 #if defined(GX_THAI_GLYPH_SHAPING_SUPPORT)
303         if (code_list)
304         {
305             if (index < code_count)
306             {
307                 char_val = code_list[index++];
308             }
309             else
310             {
311                 char_val = 0;
312             }
313         }
314         else
315         {
316 #endif
317             ret = _gx_utility_utf8_string_character_get(&string_copy, &char_val, GX_NULL);
318 #if defined(GX_THAI_GLYPH_SHAPING_SUPPORT)
319         }
320 #endif
321         if ((ret != GX_SUCCESS) || (char_val == 0))
322 #else
323         char_val = (GX_CHAR_CODE)(*string_copy.gx_string_ptr++);
324         string_copy.gx_string_length--;
325 
326         if (char_val == 0)
327 #endif /* GX_UTF8_SUPPORT */
328         {
329             break;
330         }
331 
332         font_link = font;
333         while (font_link)
334         {
335             if (char_val >= font_link -> gx_font_first_glyph &&
336                 char_val <= font_link -> gx_font_last_glyph)
337             {
338                 break;
339             }
340             font_link = font_link -> gx_font_next_page;
341         }
342 
343         if (font_link)
344         {
345             char_val = (GX_CHAR_CODE)(char_val - font_link -> gx_font_first_glyph);
346             glyph = &((GX_CONST GX_COMPRESSED_GLYPH *)font_link -> gx_font_glyphs.gx_font_compressed_glyphs)[char_val];
347 
348             /* Skip this glyph if glyph map is availlable. */
349             if (glyph -> gx_glyph_map)
350             {
351                 x_offset = (GX_VALUE)(xstart + glyph -> gx_glyph_leading);
352                 y_offset = (GX_VALUE)(ystart + font_link -> gx_font_baseline - glyph -> gx_glyph_ascent);
353 
354                 draw_area.gx_rectangle_left = x_offset;
355                 draw_area.gx_rectangle_top = y_offset;
356                 draw_area.gx_rectangle_right = (GX_VALUE)(draw_area.gx_rectangle_left + glyph -> gx_glyph_width - 1);
357                 draw_area.gx_rectangle_bottom = (GX_VALUE)(draw_area.gx_rectangle_top + glyph -> gx_glyph_height - 1);
358 
359                 if (draw_area.gx_rectangle_bottom >= view -> gx_rectangle_top &&
360                     draw_area.gx_rectangle_top <= view -> gx_rectangle_bottom &&
361                     draw_area.gx_rectangle_right >= view -> gx_rectangle_left &&
362                     draw_area.gx_rectangle_left <= view -> gx_rectangle_right)
363                 {
364 
365                     map_offset.gx_point_x = 0;
366                     map_offset.gx_point_y = 0;
367                     /* Calculate the y_start value, which is the offset into the row of
368                        the glyph where we start to the draw. */
369                     if (draw_area.gx_rectangle_top < view -> gx_rectangle_top)
370                     {
371                         map_offset.gx_point_y = (GX_VALUE)(view -> gx_rectangle_top - draw_area.gx_rectangle_top);
372                         draw_area.gx_rectangle_top = view -> gx_rectangle_top;
373                     }
374 
375                     if (draw_area.gx_rectangle_left < view -> gx_rectangle_left)
376                     {
377                         map_offset.gx_point_x = (GX_VALUE)(view -> gx_rectangle_left - x_offset);
378                         draw_area.gx_rectangle_left = view -> gx_rectangle_left;
379                     }
380 
381                     if (draw_area.gx_rectangle_bottom > view -> gx_rectangle_bottom)
382                     {
383                         draw_area.gx_rectangle_bottom = view -> gx_rectangle_bottom;
384                     }
385                     if (draw_area.gx_rectangle_right > view -> gx_rectangle_right)
386                     {
387                         draw_area.gx_rectangle_right = view -> gx_rectangle_right;
388                     }
389 
390                     draw_glyph(context, &draw_area, &map_offset, (const GX_GLYPH *)glyph);
391                 }
392             }
393             xstart = (GX_VALUE)(xstart + glyph -> gx_glyph_advance);
394         }
395     } while (string_copy.gx_string_length > 0);
396 }
397 
398 /**************************************************************************/
399 /*                                                                        */
400 /*  FUNCTION                                               RELEASE        */
401 /*                                                                        */
402 /*    _gx_canvas_generic_glyphs_draw                      PORTABLE C      */
403 /*                                                           6.1          */
404 /*  AUTHOR                                                                */
405 /*                                                                        */
406 /*    Kenneth Maxwell, Microsoft Corporation                              */
407 /*                                                                        */
408 /*  DESCRIPTION                                                           */
409 /*                                                                        */
410 /*    This function prepares to draw text.                                */
411 /*                                                                        */
412 /*  INPUT                                                                 */
413 /*                                                                        */
414 /*    context                               Drawing context               */
415 /*    font                                  Font used by the string       */
416 /*    draw_position                         Coord of draw position        */
417 /*    string                                Pointer to string which need  */
418 /*                                            to draw                     */
419 /*    length                                Number of string about to draw*/
420 /*    view                                  Pointer to view size          */
421 /*    draw_glyph                            Callback pointer to display   */
422 /*                                            driver text draw function   */
423 /*                                                                        */
424 /*  OUTPUT                                                                */
425 /*                                                                        */
426 /*                                                                        */
427 /*  CALLS                                                                 */
428 /*                                                                        */
429 /*    _gx_utility_utf8_string_character_get                               */
430 /*                                    Get characters of this string       */
431 /*                                                                        */
432 /*  CALLED BY                                                             */
433 /*                                                                        */
434 /*    _gx_canvas_glyph_draw                                               */
435 /*                                                                        */
436 /*  RELEASE HISTORY                                                       */
437 /*                                                                        */
438 /*    DATE              NAME                      DESCRIPTION             */
439 /*                                                                        */
440 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
441 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
442 /*                                            resulting in version 6.1    */
443 /*                                                                        */
444 /**************************************************************************/
_gx_canvas_generic_glyphs_draw(GX_DRAW_CONTEXT * context,GX_FONT * font,GX_POINT * draw_position,GX_CONST GX_STRING * string,GX_RECTANGLE * view,VOID (* draw_glyph)(GX_DRAW_CONTEXT *,GX_RECTANGLE *,GX_POINT *,GX_CONST GX_GLYPH *))445 static VOID _gx_canvas_generic_glyphs_draw(GX_DRAW_CONTEXT *context, GX_FONT *font, GX_POINT *draw_position, GX_CONST GX_STRING *string, GX_RECTANGLE *view,
446                                            VOID (*draw_glyph)(GX_DRAW_CONTEXT *, GX_RECTANGLE *, GX_POINT *, GX_CONST GX_GLYPH *))
447 {
448 GX_CONST GX_GLYPH *glyph;
449 GX_CHAR_CODE       char_val;
450 GX_VALUE           x_offset;
451 GX_VALUE           y_offset;
452 GX_VALUE           xstart;
453 GX_VALUE           ystart;
454 GX_POINT           map_offset;
455 GX_RECTANGLE       draw_area;
456 GX_CONST GX_FONT  *font_link;
457 GX_STRING          string_copy;
458 
459 #ifdef GX_UTF8_SUPPORT
460 UINT          ret;
461 #ifdef GX_THAI_GLYPH_SHAPING_SUPPORT
462 GX_CHAR_CODE *code_list = GX_NULL;
463 UINT          code_count;
464 UINT          index = 0;
465     if (_gx_system_text_render_style & GX_TEXT_RENDER_THAI_GLYPH_SHAPING)
466     {
467         ret = _gx_utility_thai_glyph_shaping(string, &code_list, &code_count);
468     }
469 #endif
470 #endif /* GX_UTF8_SUPPORT */
471 
472     /* Setup local variables.  */
473     xstart = draw_position -> gx_point_x;
474     ystart = draw_position -> gx_point_y;
475     string_copy = *string;
476 
477     /* for each character in the string */
478     do
479     {
480 #ifdef GX_UTF8_SUPPORT
481 #if defined(GX_THAI_GLYPH_SHAPING_SUPPORT)
482         if (code_list)
483         {
484             if (index < code_count)
485             {
486                 char_val = code_list[index++];
487             }
488             else
489             {
490                 char_val = 0;
491             }
492         }
493         else
494         {
495 #endif
496             ret = _gx_utility_utf8_string_character_get(&string_copy, &char_val, GX_NULL);
497 #if defined(GX_THAI_GLYPH_SHAPING_SUPPORT)
498         }
499 #endif
500         if ((ret != GX_SUCCESS) || (char_val == 0))
501 #else
502         char_val = (GX_CHAR_CODE)(*string_copy.gx_string_ptr++);
503         string_copy.gx_string_length--;
504 
505         if (char_val == 0)
506 #endif /* GX_UTF8_SUPPORT */
507         {
508             break;
509         }
510 
511         font_link = font;
512         while (font_link)
513         {
514             if (char_val >= font_link -> gx_font_first_glyph &&
515                 char_val <= font_link -> gx_font_last_glyph)
516             {
517                 break;
518             }
519             font_link = font_link -> gx_font_next_page;
520         }
521 
522         if (font_link)
523         {
524             char_val = (GX_CHAR_CODE)(char_val - font_link -> gx_font_first_glyph);
525             glyph = &font_link -> gx_font_glyphs.gx_font_normal_glyphs[char_val];
526 
527             if (glyph -> gx_glyph_map)
528             {
529                 x_offset = (GX_VALUE)(xstart + glyph -> gx_glyph_leading);
530                 y_offset = (GX_VALUE)(ystart + font_link -> gx_font_baseline - glyph -> gx_glyph_ascent);
531 
532                 draw_area.gx_rectangle_left = x_offset;
533                 draw_area.gx_rectangle_top = y_offset;
534                 draw_area.gx_rectangle_right = (GX_VALUE)(draw_area.gx_rectangle_left + glyph -> gx_glyph_width - 1);
535                 draw_area.gx_rectangle_bottom = (GX_VALUE)(draw_area.gx_rectangle_top + glyph -> gx_glyph_height - 1);
536 
537                 if (draw_area.gx_rectangle_bottom >= view -> gx_rectangle_top &&
538                     draw_area.gx_rectangle_top <= view -> gx_rectangle_bottom &&
539                     draw_area.gx_rectangle_right >= view -> gx_rectangle_left &&
540                     draw_area.gx_rectangle_left <= view -> gx_rectangle_right)
541                 {
542                     map_offset.gx_point_x = 0;
543                     map_offset.gx_point_y = 0;
544 
545                     /* Calculate the y_start value, which is the offset into the row of
546                        the glyph where we start to the draw. */
547                     if (draw_area.gx_rectangle_top < view -> gx_rectangle_top)
548                     {
549                         map_offset.gx_point_y = (GX_VALUE)(view -> gx_rectangle_top - draw_area.gx_rectangle_top);
550                         draw_area.gx_rectangle_top = view -> gx_rectangle_top;
551                     }
552 
553                     if (draw_area.gx_rectangle_left < view -> gx_rectangle_left)
554                     {
555                         map_offset.gx_point_x = (GX_VALUE)(view -> gx_rectangle_left - x_offset);
556                         draw_area.gx_rectangle_left = view -> gx_rectangle_left;
557                     }
558 
559                     if (draw_area.gx_rectangle_bottom > view -> gx_rectangle_bottom)
560                     {
561                         draw_area.gx_rectangle_bottom = view -> gx_rectangle_bottom;
562                     }
563                     if (draw_area.gx_rectangle_right > view -> gx_rectangle_right)
564                     {
565                         draw_area.gx_rectangle_right = view -> gx_rectangle_right;
566                     }
567 
568                     draw_glyph(context, &draw_area, &map_offset, glyph);
569                 }
570             }
571             xstart = (GX_VALUE)(xstart + glyph -> gx_glyph_advance);
572         }
573     } while (string_copy.gx_string_length > 0);
574 
575 #ifdef GX_UTF8_SUPPORT
576 #if defined(GX_THAI_GLYPH_SHAPING_SUPPORT)
577     if (code_list)
578     {
579         _gx_system_memory_free((void *)code_list);
580     }
581 #endif
582 #endif
583 }
584 
585 /**************************************************************************/
586 /*                                                                        */
587 /*  FUNCTION                                               RELEASE        */
588 /*                                                                        */
589 /*    _gx_canvas_glyphs_draw                              PORTABLE C      */
590 /*                                                           6.1          */
591 /*  AUTHOR                                                                */
592 /*                                                                        */
593 /*    Kenneth Maxwell, Microsoft Corporation                              */
594 /*                                                                        */
595 /*  DESCRIPTION                                                           */
596 /*                                                                        */
597 /*    This function prepares to draw text.                                */
598 /*                                                                        */
599 /*  INPUT                                                                 */
600 /*                                                                        */
601 /*    context                               Drawing context               */
602 /*    draw_position                         Coord of draw position        */
603 /*    string                                Pointer to string which need  */
604 /*                                            to draw                     */
605 /*    length                                Number of string about to draw*/
606 /*    view                                  Pointer to view size          */
607 /*    draw_glyph                            Callback pointer to display   */
608 /*                                            driver text draw function   */
609 /*                                                                        */
610 /*  OUTPUT                                                                */
611 /*                                                                        */
612 /*                                                                        */
613 /*  CALLS                                                                 */
614 /*                                                                        */
615 /*    _gx_utility_utf8_string_character_get                               */
616 /*                                    Get characters of this string       */
617 /*                                                                        */
618 /*  CALLED BY                                                             */
619 /*                                                                        */
620 /*    _gx_canvas_compressed_glyphs_draw                                   */
621 /*    _gx_canvas_kerning_glyphs_draw                                      */
622 /*    _gx_canvas_generic_glyphs_draw                                      */
623 /*                                                                        */
624 /*  RELEASE HISTORY                                                       */
625 /*                                                                        */
626 /*    DATE              NAME                      DESCRIPTION             */
627 /*                                                                        */
628 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
629 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
630 /*                                            resulting in version 6.1    */
631 /*                                                                        */
632 /**************************************************************************/
_gx_canvas_glyphs_draw(GX_DRAW_CONTEXT * context,GX_POINT * draw_position,GX_CONST GX_STRING * string,GX_RECTANGLE * view,VOID (* draw_glyph)(GX_DRAW_CONTEXT *,GX_RECTANGLE *,GX_POINT *,GX_CONST GX_GLYPH *))633 VOID _gx_canvas_glyphs_draw(GX_DRAW_CONTEXT *context, GX_POINT *draw_position, GX_CONST GX_STRING *string,
634                             GX_RECTANGLE *view,
635                             VOID (*draw_glyph)(GX_DRAW_CONTEXT *, GX_RECTANGLE *, GX_POINT *, GX_CONST GX_GLYPH *))
636 {
637 GX_BRUSH *brush;
638 GX_FONT  *font;
639 
640     /* pickup pointer to current drawing context */
641     context =   _gx_system_current_draw_context;
642 
643     /* get the current brush */
644     brush =     &context -> gx_draw_context_brush;
645 
646     /* get the current font and color */
647     font =      brush -> gx_brush_font;
648 
649     if (!string || !font)
650     {
651         /* Return error.  */
652         return;
653     }
654 
655     if (font -> gx_font_format & GX_FONT_FORMAT_COMPRESSED)
656     {
657         _gx_canvas_compressed_glyphs_draw(context, font, draw_position, string, view, draw_glyph);
658     }
659 #if defined(GX_FONT_KERNING_SUPPORT)
660     else if (font -> gx_font_format & GX_FONT_FORMAT_KERNING)
661     {
662         _gx_canvas_kerning_glyphs_draw(context, font, draw_position, string, view, draw_glyph);
663     }
664 #endif
665     else
666     {
667         _gx_canvas_generic_glyphs_draw(context, font, draw_position, string, view, draw_glyph);
668     }
669 }
670 
671