GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_rich_text_view_tag_enter.c Lines: 154 154 100.0 %
Date: 2026-03-06 19:21:09 Branches: 78 78 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** GUIX Component                                                        */
17
/**                                                                       */
18
/**   Rich Text View Management (Rich Text View)                          */
19
/**                                                                       */
20
/**************************************************************************/
21
22
#define GX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "gx_api.h"
28
#include "gx_rich_text_view.h"
29
#include "gx_utility.h"
30
#include "gx_system.h"
31
32
/* Define rich text end tags. */
33
static GX_CONST GX_CHAR close_tag_bold[] = "</b>";
34
static GX_CONST GX_CHAR close_tag_italic[] = "</i>";
35
static GX_CONST GX_CHAR close_tag_underline[] = "</u>";
36
static GX_CONST GX_CHAR close_tag_font[] = "</f>";
37
static GX_CONST GX_CHAR close_tag_color[] = "</c>";
38
static GX_CONST GX_CHAR close_tag_hicolor[] = "</hc>";
39
static GX_CONST GX_CHAR close_tag_align[] = "</align>";
40
41
/* Define end tag string list. */
42
static GX_CONST GX_STRING gx_rich_text_end_tag_list[] =
43
{
44
    {close_tag_bold, sizeof(close_tag_bold) - 1},
45
    {close_tag_italic, sizeof(close_tag_italic) - 1},
46
    {close_tag_underline, sizeof(close_tag_underline) - 1},
47
    {close_tag_font, sizeof(close_tag_font) - 1},
48
    {close_tag_color, sizeof(close_tag_color) - 1},
49
    {close_tag_hicolor, sizeof(close_tag_hicolor) - 1},
50
    {close_tag_align, sizeof(close_tag_align) - 1}
51
};
52
53
/* Define tag index to access tag list. */
54
enum gx_rich_text_tag_index
55
{
56
    GX_RICH_TEXT_TAG_INDEX_BOLD = 0,
57
    GX_RICH_TEXT_TAG_INDEX_ITALIC,
58
    GX_RICH_TEXT_TAG_INDEX_UNDERLINE,
59
    GX_RICH_TEXT_TAG_INDEX_FONT,
60
    GX_RICH_TEXT_TAG_INDEX_COLOR,
61
    GX_RICH_TEXT_TAG_INDEX_HICOLOR,
62
    GX_RICH_TEXT_TAG_INDEX_ALIGN
63
};
64
65
/**************************************************************************/
66
/*                                                                        */
67
/*  FUNCTION                                               RELEASE        */
68
/*                                                                        */
69
/*    _gx_rich_text_resource_id_read                      PORTABLE C      */
70
/*                                                           6.1          */
71
/*  AUTHOR                                                                */
72
/*                                                                        */
73
/*    Kenneth Maxwell, Microsoft Corporation                              */
74
/*                                                                        */
75
/*  DESCRIPTION                                                           */
76
/*                                                                        */
77
/*    Internal helper function to read resource id.                       */
78
/*                                                                        */
79
/*  INPUT                                                                 */
80
/*                                                                        */
81
/*    text                                  Pointer to rich text          */
82
/*    start_index                           Start index of the resource   */
83
/*                                            text                        */
84
/*    length                                Length of the input string    */
85
/*    resource_id                           Retrieved resource id         */
86
/*                                                                        */
87
/*  OUTPUT                                                                */
88
/*                                                                        */
89
/*    status                                                              */
90
/*                                                                        */
91
/*  CALLS                                                                 */
92
/*                                                                        */
93
/*    None                                                                */
94
/*                                                                        */
95
/*  CALLED BY                                                             */
96
/*                                                                        */
97
/*    _gx_rich_text_view_tag_open                                         */
98
/*                                                                        */
99
/**************************************************************************/
100
633
static UINT _gx_rich_text_resource_id_read(GX_STRING *text, UINT *resource_id)
101
{
102
633
UINT    status = GX_FAILURE;
103
633
UINT    id = 0;
104
CHAR    ch;
105
106
633
    if (text -> gx_string_length < 2)
107
    {
108
31
        return status;
109
    }
110
111
602
    ch = text -> gx_string_ptr[0];
112
113

602
    if ((ch > '9') || (ch < '0'))
114
    {
115
        /* Invalid id. */
116
118
        return status;
117
    }
118
119
1155
    while (text -> gx_string_length > 0)
120
    {
121
1152
        ch = text -> gx_string_ptr[0];
122
123
1152
        text -> gx_string_ptr++;
124
1152
        text -> gx_string_length--;
125
126

1152
        if ((ch <= '9') && (ch >= '0'))
127
        {
128
            /* Read id value. */
129
671
            id = id * 10 + (UINT)(ch - '0');
130
        }
131
        else
132
        {
133
481
            if (ch == '>')
134
            {
135
425
                status = GX_SUCCESS;
136
            }
137
481
            break;
138
        }
139
    }
140
141
484
    if (status == GX_SUCCESS)
142
    {
143
425
        *resource_id = id;
144
    }
145
146
484
    return status;
147
}
148
149
/**************************************************************************/
150
/*                                                                        */
151
/*  FUNCTION                                               RELEASE        */
152
/*                                                                        */
153
/*    _gx_rich_text_view_tag_open                         PORTABLE C      */
154
/*                                                           6.1          */
155
/*  AUTHOR                                                                */
156
/*                                                                        */
157
/*    Kenneth Maxwell, Microsoft Corporation                              */
158
/*                                                                        */
159
/*  DESCRIPTION                                                           */
160
/*                                                                        */
161
/*    This function detects rich text open tag from specified text        */
162
/*    position and updated rich text draw style accordion to tag type.    */
163
/*                                                                        */
164
/*  INPUT                                                                 */
165
/*                                                                        */
166
/*    view                                  Rich text view control block  */
167
/*    text                                  Text for processing           */
168
/*    format                                Current rich text format      */
169
/*    handled_bytes                         Bytes been processed          */
170
/*                                                                        */
171
/*  OUTPUT                                                                */
172
/*                                                                        */
173
/*    status                                                              */
174
/*                                                                        */
175
/*  CALLS                                                                 */
176
/*                                                                        */
177
/*    _gx_utility_string_compare            Test if two strings equal     */
178
/*                                                                        */
179
/*  CALLED BY                                                             */
180
/*                                                                        */
181
/*    _gx_rich_text_view_tag_enter                                        */
182
/*                                                                        */
183
/**************************************************************************/
184
2086
static UINT _gx_rich_text_view_tag_open(GX_RICH_TEXT_VIEW *view, GX_CONST GX_STRING *text, GX_RICH_TEXT_FORMAT *format, GX_UBYTE *handled_bytes)
185
{
186
2086
UINT                 status = GX_FAILURE;
187
GX_STRING            string;
188
GX_STRING            tag_string;
189
GX_UBYTE             alignment;
190
2086
UINT                 resource_id = 0;
191
GX_RICH_TEXT_CONTEXT context;
192
2086
UINT                 tag_index = 0;
193
194
2086
    string = *text;
195
196
2086
    context.gx_rich_text_context_format = *format;
197
198


2086
    switch (string.gx_string_ptr[1])
199
    {
200
425
    case 'b':
201
        /* <b>: bold */
202
425
        if (string.gx_string_ptr[2] == '>')
203
        {
204
397
            string.gx_string_ptr += 3;
205
397
            string.gx_string_length -= 3;
206
207
397
            format -> gx_rich_text_flags |= GX_RICH_TEXT_BOLD;
208
397
            if (format -> gx_rich_text_flags & GX_RICH_TEXT_ITALIC)
209
            {
210
247
                format -> gx_rich_text_font_id = view -> gx_rich_text_view_fonts.gx_rich_text_fonts_bold_italic_id;
211
            }
212
            else
213
            {
214
150
                format -> gx_rich_text_font_id = view -> gx_rich_text_view_fonts.gx_rich_text_fonts_bold_id;
215
            }
216
397
            tag_index = GX_RICH_TEXT_TAG_INDEX_BOLD;
217
397
            status = GX_SUCCESS;
218
        }
219
425
        break;
220
221
392
    case 'i':
222
        /* <i>: italic */
223
392
        if (string.gx_string_ptr[2] == '>')
224
        {
225
364
            string.gx_string_ptr += 3;
226
364
            string.gx_string_length -= 3;
227
228
364
            format -> gx_rich_text_flags |= GX_RICH_TEXT_ITALIC;
229
364
            if (format -> gx_rich_text_flags & GX_RICH_TEXT_BOLD)
230
            {
231
230
                format -> gx_rich_text_font_id = view -> gx_rich_text_view_fonts.gx_rich_text_fonts_bold_italic_id;
232
            }
233
            else
234
            {
235
134
                format -> gx_rich_text_font_id = view -> gx_rich_text_view_fonts.gx_rich_text_fonts_italic_id;
236
            }
237
364
            tag_index = GX_RICH_TEXT_TAG_INDEX_ITALIC;
238
364
            status = GX_SUCCESS;
239
        }
240
392
        break;
241
242
89
    case 'u':
243
        /* <u>: underline*/
244
89
        if (string.gx_string_ptr[2] == '>')
245
        {
246
61
            string.gx_string_ptr += 3;
247
61
            string.gx_string_length -= 3;
248
249
61
            format -> gx_rich_text_flags |= GX_RICH_TEXT_UNDERLINE;
250
251
61
            tag_index = GX_RICH_TEXT_TAG_INDEX_UNDERLINE;
252
61
            status = GX_SUCCESS;
253
        }
254
89
        break;
255
256
303
    case 'f':
257
        /* <f font-id>: select font */
258
303
        if (string.gx_string_ptr[2] == ' ')
259
        {
260
275
            string.gx_string_ptr += 3;
261
275
            string.gx_string_length -= 3;
262
263
            /* font id should <= 0xff */
264
275
            status = _gx_rich_text_resource_id_read(&string, &resource_id);
265
266
275
            if (status != GX_SUCCESS)
267
            {
268
68
                return status;
269
            }
270
271
207
            tag_index = GX_RICH_TEXT_TAG_INDEX_FONT;
272
207
            format -> gx_rich_text_font_id = resource_id;
273
        }
274
235
        break;
275
276
222
    case 'c':
277
        /* <c color_id>: text color */
278
222
        if (string.gx_string_ptr[2] == ' ')
279
        {
280
194
            string.gx_string_ptr += 3;
281
194
            string.gx_string_length -= 3;
282
283
194
            status = _gx_rich_text_resource_id_read(&string,  &resource_id);
284
285
194
            if (status != GX_SUCCESS)
286
            {
287
56
                return status;
288
            }
289
290
138
            tag_index = GX_RICH_TEXT_TAG_INDEX_COLOR;
291
138
            format -> gx_rich_text_color = resource_id;
292
        }
293
166
        break;
294
295
248
    case 'h':
296
        /* <hc color_id>: highlight color */
297
248
        if (string.gx_string_length > 3)
298
        {
299

220
            if (string.gx_string_ptr[2] == 'c' && string.gx_string_ptr[3] == ' ')
300
            {
301
164
                string.gx_string_ptr += 4;
302
164
                string.gx_string_length -= 4;
303
164
                status = _gx_rich_text_resource_id_read(&string, &resource_id);
304
305
164
                if (status != GX_SUCCESS)
306
                {
307
84
                    return status;
308
                }
309
310
80
                tag_index = GX_RICH_TEXT_TAG_INDEX_HICOLOR;
311
80
                format -> gx_rich_text_highlight_color = resource_id;
312
            }
313
        }
314
164
        break;
315
316
351
    case 'a':
317
        /* <align align-value>: alignment */
318
351
        tag_string.gx_string_ptr = "lign ";
319
351
        tag_string.gx_string_length = sizeof("lign ") - 1;
320
321
351
        string.gx_string_ptr += 2;
322
351
        string.gx_string_length -= 2;
323
324
351
        if (tag_string.gx_string_length <= string.gx_string_length)
325
        {
326
323
            if (_gx_utility_string_compare(&string, &tag_string, tag_string.gx_string_length) == GX_TRUE)
327
            {
328
295
                string.gx_string_ptr += tag_string.gx_string_length;
329
295
                string.gx_string_length -= tag_string.gx_string_length;
330
331

295
                switch (string.gx_string_ptr[0])
332
                {
333
117
                case 'c':
334
117
                    tag_string.gx_string_ptr = "enter>";
335
117
                    tag_string.gx_string_length = sizeof("enter>") - 1;
336
117
                    alignment = GX_RICH_TEXT_CENTER;
337
117
                    break;
338
339
61
                case 'r':
340
61
                    tag_string.gx_string_ptr = "ight>";
341
61
                    tag_string.gx_string_length = sizeof("ight>") - 1;
342
61
                    alignment = GX_RICH_TEXT_RIGHT;
343
61
                    break;
344
345
89
                case 'l':
346
89
                    tag_string.gx_string_ptr = "eft>";
347
89
                    tag_string.gx_string_length = sizeof("eft>") - 1;
348
89
                    alignment = GX_RICH_TEXT_LEFT;
349
89
                    break;
350
351
28
                default:
352
28
                    return GX_FAILURE;
353
                }
354
355
267
                string.gx_string_ptr++;
356
267
                string.gx_string_length--;
357
358
267
                if (tag_string.gx_string_length <= string.gx_string_length)
359
                {
360
239
                    if (_gx_utility_string_compare(&string, &tag_string, tag_string.gx_string_length) == GX_TRUE)
361
                    {
362
211
                        format -> gx_rich_text_flags &= (GX_UBYTE)(~GX_RICH_TEXT_ALIGN_MASK);
363
211
                        format -> gx_rich_text_flags |= alignment;
364
211
                        string.gx_string_length -= tag_string.gx_string_length;
365
366
211
                        tag_index = GX_RICH_TEXT_TAG_INDEX_ALIGN;
367
211
                        status = GX_SUCCESS;
368
                    }
369
                }
370
            }
371
        }
372
323
        break;
373
374
56
    default:
375
56
        return GX_FAILURE;
376
    }
377
378
1794
    if (status == GX_SUCCESS)
379
    {
380
1458
        context.gx_rich_text_context_tag = &gx_rich_text_end_tag_list[tag_index];
381
382
        /* Push draw style to stack. */
383
1458
        status = _gx_rich_text_view_context_push(&context);
384
    }
385
386
1794
    if (status == GX_SUCCESS)
387
    {
388
1230
        *handled_bytes = (GX_UBYTE)(text -> gx_string_length - string.gx_string_length);
389
    }
390
391
1794
    return status;
392
}
393
394
395
/**************************************************************************/
396
/*                                                                        */
397
/*  FUNCTION                                               RELEASE        */
398
/*                                                                        */
399
/*    _gx_rich_text_view_tag_close                        PORTABLE C      */
400
/*                                                           6.1          */
401
/*  AUTHOR                                                                */
402
/*                                                                        */
403
/*    Kenneth Maxwell, Microsoft Corporation                              */
404
/*                                                                        */
405
/*  DESCRIPTION                                                           */
406
/*                                                                        */
407
/*    This function detects rich text close tag from specified text       */
408
/*    position and updated rich text draw style accordion to tag type.    */
409
/*                                                                        */
410
/*  INPUT                                                                 */
411
/*                                                                        */
412
/*    text                                  Text for processing           */
413
/*    format                                Current rich text format      */
414
/*    handled_bytes                         Bytes been processed          */
415
/*                                                                        */
416
/*  OUTPUT                                                                */
417
/*                                                                        */
418
/*    status                                                              */
419
/*                                                                        */
420
/*  CALLS                                                                 */
421
/*                                                                        */
422
/*    _gx_utility_string_compare            Test if two strings equal     */
423
/*                                                                        */
424
/*  CALLED BY                                                             */
425
/*                                                                        */
426
/*    _gx_rich_text_view_tag_enter                                        */
427
/*                                                                        */
428
/**************************************************************************/
429
1095
static UINT _gx_rich_text_view_tag_close(GX_CONST GX_STRING *text, GX_RICH_TEXT_FORMAT *format, GX_UBYTE *handled_bytes)
430
{
431
1095
UINT                 status = GX_FAILURE;
432
GX_RICH_TEXT_CONTEXT context;
433
GX_CONST GX_STRING  *tag;
434
435
    /* Peek tag in top of the stack. */
436
1095
    status = _gx_rich_text_view_context_peek(&context);
437
438
1095
    if (status == GX_SUCCESS)
439
    {
440
1033
        tag = context.gx_rich_text_context_tag;
441
442
        /* Test if we meet the end tag in stack top. */
443
1033
        if (_gx_utility_string_compare(text, tag, tag -> gx_string_length) == GX_TRUE)
444
        {
445
            /* Yes, it's time to pop the style. */
446
1014
            _gx_rich_text_view_context_pop();
447
1014
            *format = context.gx_rich_text_context_format;
448
1014
            *handled_bytes = (GX_UBYTE)tag -> gx_string_length;
449
        }
450
        else
451
        {
452
19
            status = GX_FAILURE;
453
        }
454
    }
455
456
1095
    return status;
457
}
458
459
460
/**************************************************************************/
461
/*                                                                        */
462
/*  FUNCTION                                               RELEASE        */
463
/*                                                                        */
464
/*    _gx_rich_text_view_tag_enter                        PORTABLE C      */
465
/*                                                           6.1          */
466
/*  AUTHOR                                                                */
467
/*                                                                        */
468
/*    Kenneth Maxwell, Microsoft Corporation                              */
469
/*                                                                        */
470
/*  DESCRIPTION                                                           */
471
/*                                                                        */
472
/*    This function detects rich text tag from specified text position,   */
473
/*    and updated rich text draw style accordion to tag type.             */
474
/*                                                                        */
475
/*  INPUT                                                                 */
476
/*                                                                        */
477
/*    view                                  Rich text view control block  */
478
/*    text                                  Text for processing           */
479
/*    format                                Current rich text format      */
480
/*    handled_bytes                         Bytes been processed          */
481
/*                                                                        */
482
/*  OUTPUT                                                                */
483
/*                                                                        */
484
/*    status                                                              */
485
/*                                                                        */
486
/*  CALLS                                                                 */
487
/*                                                                        */
488
/*    _gx_rich_text_view_tag_open           Process open tag              */
489
/*    _gx_rich_text_view_tag_close          Prpcess close tag             */
490
/*                                                                        */
491
/*  CALLED BY                                                             */
492
/*                                                                        */
493
/*    GUIX Internal Code                                                  */
494
/*                                                                        */
495
/**************************************************************************/
496
3230
UINT _gx_rich_text_view_tag_enter(GX_RICH_TEXT_VIEW *view, GX_CONST GX_STRING *text, GX_RICH_TEXT_FORMAT *format, GX_UBYTE *handled_bytes)
497
{
498
499
3230
    if (text -> gx_string_ptr[0] != '<')
500
    {
501
        /* Tag must start with '<'. */
502
1
        return GX_FAILURE;
503
    }
504
505
3229
    if (text -> gx_string_length < 3)
506
    {
507
        /* Tag contains at least 3 character: <tag-name>, <tag-name tag-value>, </tag-name>. */
508
29
        return GX_FAILURE;
509
    }
510
511
3200
    if (text -> gx_string_ptr[1] == '/')
512
    {
513
1114
        if (text -> gx_string_length < 4)
514
        {
515
            /* Close tag contains at least 4 character: </tag-name>. */
516
19
            return GX_FAILURE;
517
        }
518
519
1095
        return _gx_rich_text_view_tag_close(text, format, handled_bytes);
520
    }
521
    else
522
    {
523
2086
        return _gx_rich_text_view_tag_open(view, text, format, handled_bytes);
524
    }
525
}
526