GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_rich_text_view_text_draw.c Lines: 131 131 100.0 %
Date: 2024-12-05 08:52:37 Branches: 52 52 100.0 %

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

12768
        if ((!escape) && (text.gx_string_ptr[0] == '\\'))
151
        {
152
36
            escape = GX_TRUE;
153
154
36
            if (draw_text.gx_string_length == 0)
155
            {
156
9
                draw_text.gx_string_ptr++;
157
            }
158
            else
159
            {
160
27
                draw_start = GX_TRUE;
161
            }
162
        }
163
        else
164
        {
165
            /* Test tags. */
166
12732
            if ((!escape) &&
167

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

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