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