GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_multi_line_text_view_text_draw.c Lines: 76 76 100.0 %
Date: 2024-12-05 08:52:37 Branches: 35 35 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
/**   Multi Line Text View Management (Multi Line 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_context.h"
30
#include "gx_multi_line_text_view.h"
31
#include "gx_utility.h"
32
#include "gx_widget.h"
33
#include "gx_window.h"
34
#include "gx_scrollbar.h"
35
36
/**************************************************************************/
37
/*                                                                        */
38
/*  FUNCTION                                               RELEASE        */
39
/*                                                                        */
40
/*    _gx_multi_line_text_view_draw                       PORTABLE C      */
41
/*                                                           6.1          */
42
/*  AUTHOR                                                                */
43
/*                                                                        */
44
/*    Kenneth Maxwell, Microsoft Corporation                              */
45
/*                                                                        */
46
/*  DESCRIPTION                                                           */
47
/*                                                                        */
48
/*    This function draws text for a multi-line-text-view widget.         */
49
/*                                                                        */
50
/*  INPUT                                                                 */
51
/*                                                                        */
52
/*    text_view                              Multi-line_text_view widget  */
53
/*                                             control block              */
54
/*    text_color                             ID of text color             */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    None                                                                */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _gx_context_line_color_set            Set the context color         */
63
/*    _gx_context_font_get                  Get font associated with the  */
64
/*                                            specified ID                */
65
/*    _gx_context_font_set                  Set the context font          */
66
/*    _gx_context_brush_width_set           Set the brush width           */
67
/*    _gx_multi_line_text_view_visible_rows_compute                       */
68
/*                                          Calculate visible rows        */
69
/*    _gx_multi_line_text_view_string_total_rows_compute                  */
70
/*                                          Calculate total rows for input*/
71
/*                                            string                      */
72
/*    _gx_utility_rectangle_resize          Offset rectangle by specified */
73
/*                                            value                       */
74
/*    _gx_utility_rectangle_overlap_detect  Detect rectangle overlaps     */
75
/*    _gx_utility_string_length_check       Test string length            */
76
/*    _gx_system_string_get                 Get string by specified id    */
77
/*    _gx_system_private_string_get         Get string pointer in         */
78
/*                                            dynamically copied string   */
79
/*                                            buffer                      */
80
/*    _gx_multi_line_text_view_paragraph_start_get                        */
81
/*                                          Get start index of a paragraph*/
82
/*    _gx_utility_bidi_paragraph_reorder    Reorder bidi text for display */
83
/*    _gx_system_string_width_get           Get string width              */
84
/*    _gx_canvas_text_draw                  Draw the text                 */
85
/*    _gx_canvas_drawing_initiate           Initiate a drawing context    */
86
/*    _gx_canvas_drawing_complete           Complete a drawing            */
87
/*                                                                        */
88
/*  CALLED BY                                                             */
89
/*                                                                        */
90
/*    Application Code                                                    */
91
/*    GUIX Internal Code                                                  */
92
/*                                                                        */
93
/*  RELEASE HISTORY                                                       */
94
/*                                                                        */
95
/*    DATE              NAME                      DESCRIPTION             */
96
/*                                                                        */
97
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
98
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
99
/*                                            support runtime Arabic      */
100
/*                                            line breaking,              */
101
/*                                            modified logic of dynamic   */
102
/*                                            bidi text draw,             */
103
/*                                            resulting in version 6.1    */
104
/*                                                                        */
105
/**************************************************************************/
106
24137
VOID  _gx_multi_line_text_view_text_draw(GX_MULTI_LINE_TEXT_VIEW *text_view, GX_RESOURCE_ID text_color)
107
{
108
INT           index;
109
INT           line_height;
110
GX_STRING     string;
111
GX_STRING     line_string;
112
INT           x_pos;
113
INT           y_pos;
114
GX_RECTANGLE  client;
115
GX_RECTANGLE  draw_area;
116
GX_CANVAS    *canvas;
117
INT           first_visible_line;
118
INT           last_visible_line;
119
UINT          line_start_index;
120
UINT          line_end_index;
121
UINT          line_cache_start;
122
GX_VALUE      text_width;
123
GX_VALUE      space_width;
124
GX_VALUE      client_width;
125
GX_FONT      *font;
126
GX_SCROLLBAR *scroll;
127
128
#if defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT)
129
GX_BIDI_RESOLVED_TEXT_INFO *next = GX_NULL;
130
UINT                        bidi_text_line_index = 0;
131
#endif
132
133
24137
    _gx_context_line_color_set(text_color);
134
24137
    _gx_context_font_get(text_view -> gx_multi_line_text_view_font_id, &font);
135
24137
    _gx_context_font_set(text_view -> gx_multi_line_text_view_font_id);
136
24137
    _gx_context_brush_width_set(1);
137
138
24137
    _gx_window_scrollbar_find((GX_WINDOW *)text_view, GX_TYPE_VERTICAL_SCROLL, &scroll);
139
140
24137
    if (text_view -> gx_multi_line_text_view_line_index_old)
141
    {
142
143
        /* Get visible rows. */
144
563
        _gx_multi_line_text_view_visible_rows_compute(text_view);
145
146
        /* Calculate text total rows. */
147
563
        _gx_multi_line_text_view_string_total_rows_compute(text_view);
148
149
563
        if (scroll)
150
        {
151
            /* Reset scrollbar.  */
152
90
            _gx_scrollbar_reset(scroll, GX_NULL);
153
        }
154
        else
155
        {
156
473
            if (text_view -> gx_multi_line_text_view_text_total_rows >
157
473
                text_view -> gx_multi_line_text_view_cache_size)
158
            {
159
                /* Update line cache. */
160
4
                _gx_multi_line_text_view_line_cache_update(text_view);
161
            }
162
        }
163
    }
164
165
    /* Is there a string and font?  */
166
24137
    if ((text_view -> gx_multi_line_text_view_text.gx_string_length <= 0)  ||
167
18590
        font == GX_NULL)
168
    {
169
5588
        return;
170
    }
171
172
    /* Pickup text height. */
173
18568
    line_height = font -> gx_font_line_height + text_view -> gx_multi_line_text_view_line_space;
174
175
18568
    if (!line_height)
176
    {
177
19
        return;
178
    }
179
180
    /* pick up current canvas */
181
18549
    canvas = _gx_system_current_draw_context -> gx_draw_context_canvas;
182
183
    /* Pick up client area.  */
184
18549
    client = text_view -> gx_window_client;
185
186
    /* Offset client area by the size of whitespace.  */
187
18549
    _gx_utility_rectangle_resize(&client, (GX_VALUE)(-text_view -> gx_multi_line_text_view_whitespace));
188
189
    /* check for auto-scrolling vertically centered text */
190
18549
    if (text_view -> gx_widget_type == GX_TYPE_MULTI_LINE_TEXT_VIEW &&
191
9058
        scroll == GX_NULL &&
192
8242
        (text_view -> gx_widget_style & GX_STYLE_VALIGN_CENTER) == GX_STYLE_VALIGN_CENTER)
193
    {
194
4
        space_width = (GX_VALUE)(client.gx_rectangle_bottom - client.gx_rectangle_top);
195
4
        space_width = (GX_VALUE)((INT)space_width - (INT)((INT)text_view -> gx_multi_line_text_view_text_total_rows * line_height));
196
4
        text_view -> gx_multi_line_text_view_text_scroll_shift = (space_width >> 1);
197
    }
198
199
18549
    _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &draw_area);
200
18549
    _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)text_view, &draw_area);
201
202
    /* Compute the start displaying position of pixels in x direction and y direction. */
203
18549
    y_pos = client.gx_rectangle_top;
204
18549
    y_pos += text_view -> gx_multi_line_text_view_text_scroll_shift;
205
18549
    y_pos += (text_view -> gx_multi_line_text_view_line_space >> 1);
206
207
18549
    line_string.gx_string_ptr = " ";
208
18549
    line_string.gx_string_length = 1;
209
210
18549
    _gx_system_string_width_get_ext(font, &line_string, &space_width);
211
212
18549
    first_visible_line = ((-text_view -> gx_multi_line_text_view_text_scroll_shift)) / line_height;
213
214
18549
    if (first_visible_line < 0)
215
    {
216
4
        first_visible_line = 0;
217
    }
218
219
18549
    last_visible_line = first_visible_line + (INT)(text_view -> gx_multi_line_text_view_text_visible_rows);
220
221
18549
    if (last_visible_line > (INT)(text_view -> gx_multi_line_text_view_text_total_rows - 1))
222
    {
223
14589
        last_visible_line = (INT)(text_view -> gx_multi_line_text_view_text_total_rows - 1);
224
    }
225
226
18549
    if (text_view -> gx_multi_line_text_view_text_id)
227
    {
228
2862
        _gx_widget_string_get_ext((GX_WIDGET *)text_view, text_view -> gx_multi_line_text_view_text_id, &string);
229
    }
230
    else
231
    {
232
15687
        _gx_system_private_string_get(&text_view -> gx_multi_line_text_view_text, &string, text_view -> gx_widget_style);
233
    }
234
235
18549
    y_pos += (INT)(first_visible_line * line_height);
236
237
115503
    for (index = first_visible_line; index <= last_visible_line; index++)
238
    {
239
#if defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT)
240
        if (_gx_system_bidi_text_enabled)
241
        {
242
            line_string.gx_string_ptr = GX_NULL;
243
            line_string.gx_string_length = 0;
244
245
            if (!next)
246
            {
247
                next = text_view -> gx_multi_line_text_view_bidi_resolved_text_info;
248
            }
249
250
            while (next)
251
            {
252
                if (bidi_text_line_index + next -> gx_bidi_resolved_text_info_total_lines > (UINT)index)
253
                {
254
                    /* Get line string. */
255
                    if (next -> gx_bidi_resolved_text_info_text)
256
                    {
257
                        line_string = next -> gx_bidi_resolved_text_info_text[(UINT)index - bidi_text_line_index];
258
                    }
259
                    break;
260
                }
261
262
                bidi_text_line_index += next -> gx_bidi_resolved_text_info_total_lines;
263
                next = next -> gx_bidi_resolved_text_info_next;
264
            }
265
        }
266
        else
267
        {
268
#endif /* defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT) */
269
96954
            line_cache_start = text_view -> gx_multi_line_text_view_first_cache_line;
270
96954
            line_start_index = text_view -> gx_multi_line_text_view_line_index[index - (INT)line_cache_start];
271
272
96954
            if ((INT)(index - (INT)line_cache_start) >= (INT)(text_view -> gx_multi_line_text_view_cache_size - 1))
273
            {
274
15120
                line_end_index = text_view -> gx_multi_line_text_view_text.gx_string_length;
275
            }
276
            else
277
            {
278
81834
                line_end_index = text_view -> gx_multi_line_text_view_line_index[index - (INT)(line_cache_start) + 1];
279
            }
280
281
            /* Get line string. */
282
96954
            line_string.gx_string_ptr = string.gx_string_ptr + line_start_index;
283
96954
            line_string.gx_string_length = line_end_index - line_start_index;
284
#if defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT)
285
        }
286
#endif /* defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT) */
287
288
289
96954
        switch (text_view -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
290
        {
291
12114
        case GX_STYLE_TEXT_RIGHT:
292
12114
            _gx_system_string_width_get_ext(font, &line_string, &text_width);
293
13042
            while (text_width > (client.gx_rectangle_right - client.gx_rectangle_left - 2))
294
            {
295
928
                text_width = (GX_VALUE)(text_width - space_width);
296
            }
297
12114
            x_pos = client.gx_rectangle_right - 1;
298
12114
            x_pos = (GX_VALUE)(x_pos - text_width);
299
12114
            break;
300
71507
        case GX_STYLE_TEXT_LEFT:
301
71507
            x_pos = client.gx_rectangle_left + 1;
302
71507
            break;
303
13333
        case GX_STYLE_TEXT_CENTER:
304
        default:
305
13333
            _gx_system_string_width_get_ext(font, &line_string, &text_width);
306
13333
            client_width = (GX_VALUE)(client.gx_rectangle_right - client.gx_rectangle_left + 1);
307
14173
            while (text_width > (client_width - 3))
308
            {
309
840
                text_width = (GX_VALUE)(text_width - space_width);
310
            }
311
13333
            x_pos = (GX_VALUE)(client.gx_rectangle_left + ((client_width - text_width) / 2));
312
13333
            break;
313
        }
314
315
        /* Draw the text. */
316
96954
        _gx_canvas_text_draw_ext((GX_VALUE)x_pos, (GX_VALUE)y_pos, &line_string);
317
96954
        y_pos += line_height;
318
    }
319
320
18549
    _gx_canvas_drawing_complete(canvas, GX_FALSE);
321
}
322