GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_system_canvas_refresh.c Lines: 51 51 100.0 %
Date: 2026-03-06 19:21:09 Branches: 36 36 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
/**   System Management (System)                                          */
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_widget.h"
31
#include "gx_utility.h"
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _gx_system_canvas_draw_partial_canvas               PORTABLE C      */
38
/*                                                           6.3.0        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Ting Zhu, Microsoft Corporation                                     */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function draws the dirty area of the specified canvas with     */
46
/*    partial canvas buffer and toggle the dirty area to the display or   */
47
/*    a composite canvas.                                                 */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    None                                                                */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    None                                                                */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    _gx_system_dirty_list_trim            Trim dirty area list          */
60
/*    _gx_canvas_drawing_initiate           Initiate drawing on canvas    */
61
/*    _gx_widget_children_draw              Draw widgets children         */
62
/*    [gx_widget_draw_function]             Call widget's drawing function*/
63
/*    _gx_canvas_drawing_complete           Complete drawing on canvas    */
64
/*    _gx_system_canvas_toggle              Toggle the frame buffer       */
65
/*    _gx_utility_rectangle_shift           Shift a rectangle             */
66
/*                                                                        */
67
/*  CALLED BY                                                             */
68
/*                                                                        */
69
/*    _gx_system_canvas_refresh                                           */
70
/*                                                                        */
71
/**************************************************************************/
72
#ifdef GX_ENABLE_CANVAS_PARTIAL_FRAME_BUFFER
73
static UINT _gx_system_canvas_draw_partial_canvas(GX_WINDOW_ROOT *root)
74
{
75
UINT           status = GX_SUCCESS;
76
GX_RECTANGLE   dirty_sum;
77
GX_RECTANGLE   dirty_frame;
78
UINT           index;
79
GX_WIDGET     *drawit;
80
GX_DIRTY_AREA *dirty_list_entry;
81
GX_CANVAS     *canvas = root -> gx_window_root_canvas;
82
GX_VALUE       dirty_width;
83
GX_VALUE       dirty_height;
84
85
#if defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL) || defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
86
GX_RECTANGLE dirty_mask;
87
88
    if (_gx_system_dirty_list_trim(&dirty_sum, root) == GX_FALSE)
89
    {
90
        return GX_SUCCESS;
91
    }
92
93
    dirty_mask = dirty_sum;
94
#endif
95
96
    /* Refresh canvas in the dirty area.  */
97
    if (canvas -> gx_canvas_draw_count > 0)
98
    {
99
        _gx_system_dirty_partial_add((GX_WIDGET *)root, &canvas -> gx_canvas_dirty_area);
100
        canvas -> gx_canvas_draw_count = 0;
101
    }
102
103
#if defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL)
104
    dirty_height = (GX_VALUE)(dirty_sum.gx_rectangle_bottom - dirty_sum.gx_rectangle_top + 1);
105
    dirty_width = (GX_VALUE)(canvas -> gx_canvas_memory_size / canvas -> gx_canvas_display -> gx_display_driver_row_pitch_get((USHORT)dirty_height));
106
    dirty_width = (GX_VALUE)(dirty_width & 0xFFFC);
107
    dirty_mask.gx_rectangle_right = (GX_VALUE)(dirty_mask.gx_rectangle_left + dirty_width - 1);
108
109
    while (dirty_mask.gx_rectangle_left <= dirty_sum.gx_rectangle_right)
110
    {
111
        if (dirty_mask.gx_rectangle_right > dirty_sum.gx_rectangle_right)
112
        {
113
            dirty_mask.gx_rectangle_right = dirty_sum.gx_rectangle_right;
114
        }
115
#elif defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
116
    dirty_width = (GX_VALUE)(dirty_sum.gx_rectangle_right - dirty_sum.gx_rectangle_left + 1);
117
    dirty_height = (GX_VALUE)(canvas -> gx_canvas_memory_size / canvas -> gx_canvas_display -> gx_display_driver_row_pitch_get((USHORT)((dirty_width + 3) & 0xFFFC)));
118
    dirty_mask.gx_rectangle_bottom = (GX_VALUE)(dirty_mask.gx_rectangle_top + dirty_height - 1);
119
120
    while (dirty_mask.gx_rectangle_top <= dirty_sum.gx_rectangle_bottom)
121
    {
122
        if (dirty_mask.gx_rectangle_bottom > dirty_sum.gx_rectangle_bottom)
123
        {
124
            dirty_mask.gx_rectangle_bottom = dirty_sum.gx_rectangle_bottom;
125
        }
126
#endif
127
128
        /* Initialize dirty area pointers.  */
129
        dirty_list_entry = canvas -> gx_canvas_dirty_list;
130
131
        /* Loop through dirty areas to redraw as needed.  */
132
        for (index = 0; index < canvas -> gx_canvas_dirty_count; index++)
133
        {
134
            /* Pickup widget associated with dirty area.  */
135
            drawit = dirty_list_entry -> gx_dirty_area_widget;
136
137
            /* Is the widget pointer valid?  */
138
139
            if (drawit && (drawit -> gx_widget_status & GX_STATUS_VISIBLE))
140
            {
141
                /* if the object is transparent, we need to draw the parent.
142
                    This should not happen, because dircty_partial_add checks
143
                    for transparency, but just for safety we test again here  */
144
145
                if (drawit -> gx_widget_status & GX_STATUS_TRANSPARENT ||
146
                    drawit -> gx_widget_style & (GX_STYLE_BORDER_RAISED | GX_STYLE_BORDER_RECESSED))
147
                {
148
                    while (drawit -> gx_widget_parent)
149
                    {
150
                        drawit = drawit -> gx_widget_parent;
151
152
                        if (!(drawit -> gx_widget_status & GX_STATUS_TRANSPARENT))
153
                        {
154
                            /* we need to start drawing at this non-transparent
155
                                background widget */
156
157
                            drawit -> gx_widget_status |= GX_STATUS_DIRTY;
158
                            break;
159
                        }
160
                    }
161
                }
162
163
#if defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL) || defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
164
                if (_gx_utility_rectangle_overlap_detect(&dirty_list_entry -> gx_dirty_area_rectangle, &dirty_mask, &dirty_frame) == GX_TRUE &&
165
                    _gx_utility_rectangle_overlap_detect(&dirty_frame, &drawit -> gx_widget_clip, &dirty_frame) == GX_TRUE)
166
                {
167
#else
168
                dirty_sum = dirty_list_entry -> gx_dirty_area_rectangle;
169
                if (_gx_utility_rectangle_overlap_detect(&dirty_sum, &drawit -> gx_widget_clip, &dirty_sum) == GX_TRUE)
170
                {
171
                    dirty_frame = dirty_sum;
172
173
                    /* Split dirty area into small pieces.  */
174
                    dirty_width = (GX_VALUE)(dirty_frame.gx_rectangle_right - dirty_frame.gx_rectangle_left + 1);
175
                    dirty_height = (GX_VALUE)(canvas -> gx_canvas_memory_size / canvas -> gx_canvas_display -> gx_display_driver_row_pitch_get((USHORT)((dirty_width + 3) & 0xFFFC)));
176
                    dirty_frame.gx_rectangle_bottom = (GX_VALUE)(dirty_frame.gx_rectangle_top + dirty_height - 1);
177
178
                    while (dirty_frame.gx_rectangle_top <= dirty_sum.gx_rectangle_bottom)
179
                    {
180
                        if (dirty_frame.gx_rectangle_bottom > dirty_sum.gx_rectangle_bottom)
181
                        {
182
                            dirty_frame.gx_rectangle_bottom = dirty_sum.gx_rectangle_bottom;
183
                        }
184
#endif
185
186
                    /* Initiate drawing on this canvas.  */
187
                    status = _gx_canvas_drawing_initiate(canvas, drawit, &dirty_frame);
188
189
                    if (status == GX_NO_VIEWS)
190
                    {
191
                        /* If we are attempting to draw the root window and it has no views,
192
                            just draw the children of the root */
193
194
                        if (drawit -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
195
                        {
196
                            _gx_widget_children_draw(drawit);
197
                        }
198
                    }
199
                    else
200
                    {
201
                        drawit -> gx_widget_draw_function(drawit);
202
                    }
203
204
                    /* Indicate that drawing on this canvas is complete.  */
205
                    _gx_canvas_drawing_complete(canvas, GX_TRUE);
206
207
#if !defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL) && !defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
208
                    _gx_utility_rectangle_shift(&dirty_frame, 0, dirty_height);
209
                }
210
#endif
211
            }
212
        }
213
214
        /* Move to the next dirty area.  */
215
        dirty_list_entry++;
216
    }
217
218
#ifdef GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL
219
    _gx_utility_rectangle_shift(&dirty_mask, dirty_width, 0);
220
}
221
#elif defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
222
    _gx_utility_rectangle_shift(&dirty_mask, 0, dirty_height);
223
}
224
#endif
225
226
canvas -> gx_canvas_dirty_count = 0;
227
228
return GX_SUCCESS;
229
}
230
#endif
231
232
/**************************************************************************/
233
/*                                                                        */
234
/*  FUNCTION                                               RELEASE        */
235
/*                                                                        */
236
/*    _gx_system_canvas_refresh                           PORTABLE C      */
237
/*                                                           6.3.0        */
238
/*  AUTHOR                                                                */
239
/*                                                                        */
240
/*    Kenneth Maxwell, Microsoft Corporation                              */
241
/*                                                                        */
242
/*  DESCRIPTION                                                           */
243
/*                                                                        */
244
/*    This function refreshes the screen(s) of GUIX.                      */
245
/*                                                                        */
246
/*  INPUT                                                                 */
247
/*                                                                        */
248
/*    None                                                                */
249
/*                                                                        */
250
/*  OUTPUT                                                                */
251
/*                                                                        */
252
/*    None                                                                */
253
/*                                                                        */
254
/*  CALLS                                                                 */
255
/*                                                                        */
256
/*    GX_ENTER_CRITICAL                     Enter GUIX critical section   */
257
/*    _gx_system_views_update               Update views                  */
258
/*    _gx_system_dirty_list_trim            Trim dirty area list          */
259
/*    _gx_canvas_drawing_initiate           Initiate drawing on canvas    */
260
/*    _gx_widget_children_draw              Draw widgets children         */
261
/*    [gx_widget_draw_function]             Call widget's drawing function*/
262
/*    _gx_canvas_drawing_complete           Complete drawing on canvas    */
263
/*    _gx_canvas_composite_create           Create a canvas composite     */
264
/*    [gx_display_driver_buffer_toggle]     Toggle the frame buffer       */
265
/*    GX_EXIT_CRITICAL                      Exit GUIX critical section    */
266
/*                                                                        */
267
/*  CALLED BY                                                             */
268
/*                                                                        */
269
/*    GUIX Internal Code                                                  */
270
/*                                                                        */
271
/**************************************************************************/
272
148599
UINT  _gx_system_canvas_refresh(VOID)
273
{
274
148599
UINT            status = GX_SUCCESS;
275
UINT            index;
276
GX_DIRTY_AREA  *dirty;
277
GX_WIDGET      *drawit;
278
GX_CANVAS      *canvas;
279
GX_RECTANGLE    dirty_sum;
280
GX_WINDOW_ROOT *root;
281
282
    /* Determine if there are no canvas or screens created.  */
283
148599
    if (!_gx_system_canvas_created_list)
284
    {
285
2
        return GX_INVALID_CANVAS;
286
    }
287
288
    /* lock access to GUIX */
289
148597
    GX_ENTER_CRITICAL
290
291
148597
    canvas = GX_NULL;
292
293
    /* check to see if viewports need to be recalculated */
294
148597
    root = _gx_system_root_window_created_list;
295
296
389276
    while (root)
297
    {
298
240679
        if (!(root -> gx_widget_status & GX_STATUS_VISIBLE))
299
        {
300
83857
            root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
301
83857
            continue;
302
        }
303
304
156822
        if (root -> gx_window_root_views_changed)
305
        {
306
1881
            _gx_system_views_update(root);
307
        }
308
309
        /* pick up the canvas pointer */
310
156822
        canvas = root -> gx_window_root_canvas;
311
312
#ifdef GX_ENABLE_CANVAS_PARTIAL_FRAME_BUFFER
313
        if (canvas -> gx_canvas_status & GX_CANVAS_PARTIAL_FRAME_BUFFER)
314
        {
315
            _gx_system_canvas_draw_partial_canvas(root);
316
            root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
317
            continue;
318
        }
319
#endif
320
321
        /* Trim any redundant dirty areas prior to doing the update.  */
322
156822
        if (_gx_system_dirty_list_trim(&dirty_sum, root))
323
        {
324
            /* Initiate drawing on this canvas.  */
325
122161
            _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)root, &dirty_sum);
326
327
            /* Initialize dirty area pointers.  */
328
122161
            dirty = canvas -> gx_canvas_dirty_list;
329
330
            /* Loop through dirty areas to redraw as needed.  */
331
406011
            for (index = 0; index < canvas -> gx_canvas_dirty_count; index++)
332
            {
333
                /* Pickup widget associated with dirty area.  */
334
283850
                drawit = dirty -> gx_dirty_area_widget;
335
336
                /* Is the widget pointer valid?  */
337
338
283850
                if (drawit)
339
                {
340
                    /* if the object is transparent, we need to draw the parent.
341
                       This should not happen, because dircty_partial_add checks
342
                       for transparency, but just for safety we test again here  */
343
344
225549
                    if (drawit -> gx_widget_status & GX_STATUS_TRANSPARENT)
345
                    {
346
10
                        while (drawit -> gx_widget_parent)
347
                        {
348
5
                            drawit = drawit -> gx_widget_parent;
349
350
5
                            if (!(drawit -> gx_widget_status & GX_STATUS_TRANSPARENT))
351
                            {
352
                                /* we need to start drawing at this non-transparent
353
                                   background widget */
354
355
4
                                drawit -> gx_widget_status |= GX_STATUS_DIRTY;
356
4
                                break;
357
                            }
358
                        }
359
                    }
360
361
                    /* Initiate drawing on this canvas.  */
362
363
225549
                    status = _gx_canvas_drawing_initiate(canvas, drawit,
364
                                                         &dirty -> gx_dirty_area_rectangle);
365
366
225549
                    if (status == GX_NO_VIEWS)
367
                    {
368
                        /* If we are attempting to draw the root window and it has no views,
369
                           just draw the children of the root */
370
371
43951
                        if (drawit -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
372
                        {
373
43947
                            _gx_widget_children_draw(drawit);
374
                        }
375
                    }
376
                    else
377
                    {
378
181598
                        drawit -> gx_widget_draw_function(drawit);
379
                    }
380
381
                    /* Indicate that drawing on this canvas is complete.  */
382
225549
                    _gx_canvas_drawing_complete(canvas, GX_FALSE);
383
                }
384
                /* Move to the next dirty area.  */
385
283850
                dirty++;
386
            }
387
            /* Indicate that drawing on this canvas is complete.  */
388
122161
            _gx_canvas_drawing_complete(canvas, GX_FALSE);
389
        }
390
156822
        root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
391
    }
392
393
    /* if compositing is enabled, create the composite here, rather than
394
       in the driver. Most of the code is common */
395
396
148597
    if (_gx_canvas_composite_create(&canvas))
397
    {
398
8244
        if (canvas -> gx_canvas_draw_count > 0)
399
        {
400
6148
            canvas -> gx_canvas_display -> gx_display_driver_buffer_toggle(canvas, &canvas -> gx_canvas_dirty_area);
401
6148
            canvas -> gx_canvas_draw_count = 0;
402
        }
403
    }
404
    else
405
    {
406
        /* Reset the dirty area counts  */
407
140353
        root = _gx_system_root_window_created_list;
408
409
364038
        while (root)
410
        {
411
223685
            canvas = root -> gx_window_root_canvas;
412
413
            /* reset the canvas dirty counter */
414
223685
            canvas -> gx_canvas_dirty_count = 0;
415
416
223685
            if (root -> gx_widget_status & GX_STATUS_VISIBLE)
417
            {
418
140358
                if (canvas -> gx_canvas_draw_count > 0)
419
                {
420
                    /* Call the driver buffer toggle function for this canvas.  */
421
422
112315
                    if ((canvas -> gx_canvas_status & GX_CANVAS_MANAGED_VISIBLE) == GX_CANVAS_MANAGED_VISIBLE)
423
                    {
424
112309
                        canvas -> gx_canvas_display -> gx_display_driver_buffer_toggle(canvas, &canvas -> gx_canvas_dirty_area);
425
                    }
426
                }
427
            }
428
            /* reset the canvas draw counter */
429
223685
            canvas -> gx_canvas_draw_count = 0;
430
223685
            root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
431
        }
432
    }
433
434
    /* unlock access to GUIX */
435
148597
    GX_EXIT_CRITICAL
436
437
148597
    return status;
438
}
439