GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_rich_text_view_text_draw.c Lines: 131 131 100.0 %
Date: 2026-03-06 19:21:09 Branches: 52 52 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_system.h"
29
#include "gx_canvas.h"
30
#include "gx_rich_text_view.h"
31
#include "gx_window.h"
32
#include "gx_utility.h"
33
#include "gx_widget.h"
34
#include "gx_context.h"
35
#include "gx_scrollbar.h"
36
37
/**************************************************************************/
38
/*                                                                        */
39
/*  FUNCTION                                               RELEASE        */
40
/*                                                                        */
41
/*    _gx_rich_text_view_single_line_draw                 PORTABLE C      */
42
/*                                                           6.1.5        */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    Kenneth Maxwell, Microsoft Corporation                              */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function draws a single line text for a rich text view widget. */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    text_view                              Rich text view control block */
54
/*    ypos                                   Draw start y position        */
55
/*    line_info                              Text information for drawing */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    None                                                                */
60
/*                                                                        */
61
/*  CALLS                                                                 */
62
/*                                                                        */
63
/*    _gx_rich_text_view_tag_enter          Detect rich text enter tag    */
64
/*    _gx_system_rich_text_format_pop       Pop rich text format          */
65
/*    _gx_system_rich_text_format_push      Push rich text format         */
66
/*    _gx_widget_font_get                   Retrieve font by font id      */
67
/*    _gx_system_string_width_get           Get string width              */
68
/*    _gx_canvas_text_draw                  Draw text                     */
69
/*    _gx_canvas_line_draw                  Draw line                     */
70
/*                                                                        */
71
/*  CALLED BY                                                             */
72
/*                                                                        */
73
/*    _gx_rich_text_view_draw                                             */
74
/*                                                                        */
75
/**************************************************************************/
76
939
static VOID _gx_rich_text_view_single_line_draw(GX_RICH_TEXT_VIEW *text_view, GX_VALUE ypos, GX_RICH_TEXT_LINE_INFO *line_info)
77
{
78
939
GX_STRING           text = line_info -> gx_rich_text_line_info_text;
79
GX_STRING           draw_text;
80
GX_UBYTE            processed_count;
81
GX_FONT            *font;
82
939
GX_BOOL             draw_start = GX_FALSE;
83
GX_VALUE            text_width;
84
GX_VALUE            xpos;
85
GX_VALUE            y;
86
GX_RICH_TEXT_FORMAT start_format;
87
939
GX_RICH_TEXT_FORMAT format = line_info -> gx_rich_text_line_info_start_format;
88
939
GX_RECTANGLE        client = text_view -> gx_window_client;
89
GX_VALUE            client_width;
90
GX_RECTANGLE        draw_area;
91
939
GX_BOOL             escape = GX_FALSE;
92
93
    /* Offset client area by the size of whitespace.  */
94
939
    _gx_utility_rectangle_resize(&client, (GX_VALUE)(-text_view -> gx_multi_line_text_view_whitespace));
95
96
    /* Calculate client width. */
97
939
    client_width = (GX_VALUE)(client.gx_rectangle_right - client.gx_rectangle_left);
98
99
    /* Process proceding styles. */
100
1311
    while (text.gx_string_ptr[0] == '<')
101
    {
102
610
        if ((_gx_rich_text_view_tag_enter(text_view, &text, &format, &processed_count) == GX_SUCCESS))
103
        {
104
372
            text.gx_string_ptr += processed_count;
105
372
            text.gx_string_length -= processed_count;
106
        }
107
        else
108
        {
109
238
            break;
110
        }
111
    }
112
113
939
    start_format = format;
114
115
    /* Calculate draw start x coordinate. */
116
939
    switch (format.gx_rich_text_flags & GX_RICH_TEXT_ALIGN_MASK)
117
    {
118
177
    case GX_RICH_TEXT_RIGHT:
119
177
        xpos = (GX_VALUE)(client.gx_rectangle_right - 1);
120
177
        xpos = (GX_VALUE)(xpos - (INT)line_info -> gx_rich_text_line_info_text_width);
121
177
        break;
122
123
347
    case GX_RICH_TEXT_CENTER:
124
347
        xpos = (GX_VALUE)((client_width - (INT)line_info -> gx_rich_text_line_info_text_width) / 2);
125
347
        xpos = (GX_VALUE)(xpos + client.gx_rectangle_left);
126
347
        break;
127
128
415
    case GX_RICH_TEXT_LEFT:
129
    default:
130
415
        xpos = (GX_VALUE)(client.gx_rectangle_left + 1);
131
415
        break;
132
    }
133
134
939
    draw_text.gx_string_ptr = text.gx_string_ptr;
135
939
    draw_text.gx_string_length = 0;
136
137
    /* Calculate the total rows of text view string. */
138
13707
    while (text.gx_string_length > 0)
139
    {
140
12768
        processed_count = 1;
141
142

12768
        if ((!escape) && (text.gx_string_ptr[0] == '\\'))
143
        {
144
36
            escape = GX_TRUE;
145
146
36
            if (draw_text.gx_string_length == 0)
147
            {
148
9
                draw_text.gx_string_ptr++;
149
            }
150
            else
151
            {
152
27
                draw_start = GX_TRUE;
153
            }
154
        }
155
        else
156
        {
157
            /* Test tags. */
158
12732
            if ((!escape) &&
159

13605
                (text.gx_string_ptr[0] == '<') &&
160
909
                (_gx_rich_text_view_tag_enter(text_view, &text, &format, &processed_count) == GX_SUCCESS))
161
            {
162
570
                if (draw_text.gx_string_length == 0)
163
                {
164
                    /* Skip tags. */
165
88
                    draw_text.gx_string_ptr += processed_count;
166
167
                    /* Set text draw style to current draw style. */
168
88
                    start_format = format;
169
                }
170
                else
171
                {
172
                    /* Draw text before current tag. */
173
482
                    draw_start = GX_TRUE;
174
                }
175
            }
176
            else
177
            {
178
12162
                draw_text.gx_string_length += processed_count;
179
            }
180
181
12732
            escape = GX_FALSE;
182
        }
183
184
12768
        text.gx_string_ptr += processed_count;
185
12768
        text.gx_string_length -= processed_count;
186
187
        /* If we come the the last character, or draw_text falg is true, process drawing. */
188

12768
        if ((text.gx_string_length == 0) || draw_start)
189
        {
190
            /* Pick up text font. */
191
1398
            _gx_context_font_get(start_format.gx_rich_text_font_id, &font);
192
193
            /* Pict up text width. */
194
1398
            _gx_system_string_width_get_ext(font, &draw_text, &text_width);
195
196
            /* Set text color. */
197
1398
            _gx_context_line_color_set(start_format.gx_rich_text_color);
198
199
            /* Set font. */
200
1398
            _gx_context_font_set(start_format.gx_rich_text_font_id);
201
202
1398
            if (start_format.gx_rich_text_highlight_color != text_view -> gx_widget_normal_fill_color)
203
            {
204
37
                _gx_context_brush_width_set(0);
205
206
                /* Draw highlight background. */
207
37
                _gx_context_fill_color_set(start_format.gx_rich_text_highlight_color);
208
209
37
                draw_area.gx_rectangle_left = (GX_VALUE)xpos;
210
37
                draw_area.gx_rectangle_right = (GX_VALUE)(xpos + text_width - 1);
211
37
                draw_area.gx_rectangle_top = (GX_VALUE)(ypos - (text_view -> gx_multi_line_text_view_line_space >> 1));
212
37
                draw_area.gx_rectangle_bottom = (GX_VALUE)(draw_area.gx_rectangle_top + line_info -> gx_rich_text_line_info_line_height - 1);
213
214
37
                _gx_canvas_rectangle_draw(&draw_area);
215
            }
216
217
1398
            y = (GX_VALUE)(ypos + line_info -> gx_rich_text_line_info_baseline - font -> gx_font_baseline);
218
219
            /* Draw text. */
220
1398
            _gx_canvas_text_draw_ext(xpos, y, &draw_text);
221
222
            /* Test italic flag is valid. */
223
1398
            if (start_format.gx_rich_text_flags & GX_RICH_TEXT_UNDERLINE)
224
            {
225
38
                y = (GX_VALUE)(ypos + line_info -> gx_rich_text_line_info_baseline + 1);
226
227
38
                _gx_context_brush_width_set(1);
228
229
                /* Draw underline. */
230
38
                _gx_canvas_line_draw(xpos, y, (GX_VALUE)(xpos + text_width - 1), y);
231
            }
232
233
            /* Advance draw start x position by text width. */
234
1398
            xpos = (GX_VALUE)(xpos + text_width);
235
236
1398
            draw_text.gx_string_ptr = text.gx_string_ptr;
237
1398
            draw_text.gx_string_length = 0;
238
239
            /* Set draw text flag to false. */
240
1398
            draw_start = GX_FALSE;
241
1398
            start_format = format;
242
        }
243
    }
244
245
939
    line_info -> gx_rich_text_line_info_end_format = format;
246
939
}
247
248
249
/**************************************************************************/
250
/*                                                                        */
251
/*  FUNCTION                                               RELEASE        */
252
/*                                                                        */
253
/*    _gx_rich_text_view_text_draw                        PORTABLE C      */
254
/*                                                           6.1          */
255
/*  AUTHOR                                                                */
256
/*                                                                        */
257
/*    Kenneth Maxwell, Microsoft Corporation                              */
258
/*                                                                        */
259
/*  DESCRIPTION                                                           */
260
/*                                                                        */
261
/*    This function draws text for a rich text view widget.               */
262
/*                                                                        */
263
/*  INPUT                                                                 */
264
/*                                                                        */
265
/*    text_view                              Rich text view control block */
266
/*                                                                        */
267
/*  OUTPUT                                                                */
268
/*                                                                        */
269
/*    None                                                                */
270
/*                                                                        */
271
/*  CALLS                                                                 */
272
/*                                                                        */
273
/*    _gx_window_scrollbar_find             Find scroll bar for specified */
274
/*                                          window.                       */
275
/*    _gx_rich_text_view_text_total_height_calculate                      */
276
/*                                          Calculate text total height   */
277
/*    _gx_scrollbar_reset                   Reset scrollbar               */
278
/*    _gx_utility_rectangle_resize          Resize rectangle              */
279
/*    _gx_widget_string_get_ext             Retrieve text by id           */
280
/*    _gx_widget_font_get                   Retireve font by id           */
281
/*    _gx_system_private_string_get         Retreive string pointer       */
282
/*    _gx_system_rich_text_format_stack_clear                             */
283
/*                                          Clear rich text format stack  */
284
/*    _gx_system_rich_text_format_stack_switch                            */
285
/*                                          Switch rich text format stack */
286
/*    _gx_rich_text_view_line_info_get      Get one line text for drawing */
287
/*    _gx_rich_text_view_single_line_text_draw                            */
288
/*                                          Draw a single line            */
289
/*                                                                        */
290
/*  CALLED BY                                                             */
291
/*                                                                        */
292
/*    GUIX Internal Code                                                  */
293
/*    Application Code                                                    */
294
/*                                                                        */
295
/**************************************************************************/
296
328
VOID  _gx_rich_text_view_text_draw(GX_RICH_TEXT_VIEW *text_view)
297
{
298
GX_STRING              text;
299
GX_FONT               *font;
300
GX_SCROLLBAR          *scroll;
301
GX_RICH_TEXT_LINE_INFO line_info;
302
GX_RICH_TEXT_FORMAT    format;
303
GX_VALUE               client_width;
304
GX_RECTANGLE           client;
305
GX_VALUE               ypos;
306
GX_CANVAS             *canvas;
307
GX_RECTANGLE           draw_area;
308
309
328
    if (!text_view -> gx_multi_line_text_view_text.gx_string_length)
310
    {
311
        /* Nothing to draw. */
312
1
        return;
313
    }
314
315
327
    if (text_view -> gx_multi_line_text_view_line_index_old)
316
    {
317
318
        /* Rich text layout changes, we might need to reset scrollbar. */
319
57
        _gx_window_scrollbar_find((GX_WINDOW *)text_view, GX_TYPE_VERTICAL_SCROLL, &scroll);
320
321
57
        if (scroll)
322
        {
323
            /* Update rich text view text total height.  */
324
42
            _gx_rich_text_view_text_total_height_calculate(text_view);
325
326
            /* Reset scrollbar.  */
327
42
            _gx_scrollbar_reset(scroll, GX_NULL);
328
        }
329
    }
330
331
    /* Pick up client retangle. */
332
327
    client = text_view -> gx_window_client;
333
334
    /* Offset client area by the size of whitespace.  */
335
327
    _gx_utility_rectangle_resize(&client, (GX_VALUE)(-text_view -> gx_multi_line_text_view_whitespace));
336
337
    /* Calculate text display width. */
338
327
    client_width = (GX_VALUE)(client.gx_rectangle_right - client.gx_rectangle_left - 1);
339
340
    /* Set default draw style. */
341
327
    format.gx_rich_text_color = text_view -> gx_multi_line_text_view_normal_text_color;
342
327
    format.gx_rich_text_highlight_color = text_view -> gx_widget_normal_fill_color;
343
327
    format.gx_rich_text_font_id = text_view -> gx_rich_text_view_fonts.gx_rich_text_fonts_normal_id;
344
327
    format.gx_rich_text_flags = 0;
345
346
327
    switch (text_view -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
347
    {
348
96
    case GX_STYLE_TEXT_CENTER:
349
96
        format.gx_rich_text_flags |= GX_RICH_TEXT_CENTER;
350
96
        break;
351
352
66
    case GX_STYLE_TEXT_RIGHT:
353
66
        format.gx_rich_text_flags |= GX_RICH_TEXT_RIGHT;
354
66
        break;
355
356
165
    default:
357
        /* Do nothing. */
358
165
        break;
359
    }
360
361
    /* Pick up text for drawing. */
362
327
    if (text_view -> gx_multi_line_text_view_text_id)
363
    {
364
314
        _gx_widget_string_get_ext((GX_WIDGET *)text_view, text_view -> gx_multi_line_text_view_text_id, &text);
365
    }
366
    else
367
    {
368
13
        _gx_system_private_string_get(&text_view -> gx_multi_line_text_view_text, &text, text_view -> gx_widget_style);
369
    }
370
371
327
    ypos = client.gx_rectangle_top;
372
327
    ypos = (GX_VALUE)(ypos + text_view -> gx_multi_line_text_view_text_scroll_shift);
373
327
    ypos = (GX_VALUE)(ypos + (text_view -> gx_multi_line_text_view_line_space >> 1));
374
375
    /* pick up current canvas */
376
327
    canvas = _gx_system_current_draw_context -> gx_draw_context_canvas;
377
378
327
    _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &draw_area);
379
327
    _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)text_view, &draw_area);
380
381
    /* Calculate the total rows of text view string. */
382
1279
    while (text.gx_string_length > 0)
383
    {
384
        /* Pickup draw font. */
385
986
        _gx_widget_font_get((GX_WIDGET *)text_view, format.gx_rich_text_font_id, &font);
386
387
986
        if (!font)
388
        {
389
3
            break;
390
        }
391
392
983
        line_info.gx_rich_text_line_info_text.gx_string_ptr = text.gx_string_ptr;
393
983
        line_info.gx_rich_text_line_info_text.gx_string_length = 0;
394
983
        line_info.gx_rich_text_line_info_start_format = format;
395
983
        line_info.gx_rich_text_line_info_end_format = format;
396
983
        line_info.gx_rich_text_line_info_line_height = font -> gx_font_line_height;
397
983
        line_info.gx_rich_text_line_info_baseline = font -> gx_font_baseline;
398
983
        line_info.gx_rich_text_line_info_text_width = 0;
399
400
983
        _gx_rich_text_view_context_save();
401
402
983
        if (_gx_rich_text_view_line_info_get(text_view, text, &line_info, client_width) != GX_SUCCESS)
403
        {
404
3
            break;
405
        }
406
407
980
        format = line_info.gx_rich_text_line_info_end_format;
408
409
        /* Draw text. */
410
980
        if ((GX_VALUE)(ypos + line_info.gx_rich_text_line_info_line_height) > client.gx_rectangle_top)
411
        {
412
967
            if ((GX_VALUE)(ypos) < client.gx_rectangle_bottom)
413
            {
414
939
                _gx_rich_text_view_context_restore();
415
939
                _gx_rich_text_view_single_line_draw(text_view, ypos, &line_info);
416
            }
417
            else
418
            {
419
28
                break;
420
            }
421
        }
422
423
952
        ypos = (GX_VALUE)(ypos + line_info.gx_rich_text_line_info_line_height);
424
952
        ypos = (GX_VALUE)(ypos + text_view -> gx_multi_line_text_view_line_space);
425
426
952
        text.gx_string_ptr += line_info.gx_rich_text_line_info_text.gx_string_length;
427
952
        text.gx_string_length -= line_info.gx_rich_text_line_info_text.gx_string_length;
428
    }
429
327
    _gx_canvas_drawing_complete(canvas, GX_FALSE);
430
431
327
    _gx_rich_text_view_context_reset();
432
}
433