GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_system_canvas_refresh.c Lines: 54 54 100.0 %
Date: 2026-08-28 02:37:13 Branches: 40 42 95.2 %

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