GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_canvas_drawing_initiate.c Lines: 54 54 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
/**   Canvas Management (Canvas)                                          */
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_utility.h"
30
#include "gx_canvas.h"
31
#include "gx_context.h"
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _gx_canvas_drawing_initiate                         PORTABLE C      */
38
/*                                                           6.3.0        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Kenneth Maxwell, Microsoft Corporation                              */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function initiates drawing on the specified canvas.            */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    canvas                                Canvas control block          */
50
/*    who                                   Widget control block pointer  */
51
/*    dirty_area                            Area to draw on               */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    status                                Completion status             */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    _gx_utility_rectangle_define          Define rectangle area.        */
60
/*    _gx_utility_rectangle_combine         Combine adjacent dirty areas. */
61
/*    _gx_context_brush_default             Define a brush                */
62
/*    _gx_system_error_process              Process an error              */
63
/*    _gx_utility_rectangle_overlap_detect  Detects two rectangles being  */
64
/*                                            overlap                     */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    Application Code                                                    */
69
/*    _gx_multi_line_text_view_draw                                       */
70
/*    _gx_single_line_text_view_draw                                      */
71
/*    _gx_system_canvas_refresh                                           */
72
/*    _gx_widget_block_move                                               */
73
/*    _gx_widget_children_draw                                            */
74
/*    _gx_window_client_scroll                                            */
75
/*                                                                        */
76
/**************************************************************************/
77
1882191
UINT _gx_canvas_drawing_initiate(GX_CANVAS *canvas, GX_WIDGET *who, GX_RECTANGLE *dirty_area)
78
{
79
GX_WINDOW       *win;
80
GX_DRAW_CONTEXT *new_context;
81
1882191
GX_DRAW_CONTEXT *current_context = _gx_system_current_draw_context;
82
1882191
GX_DISPLAY      *display = canvas -> gx_canvas_display;
83
84
1882191
    if (current_context)
85
    {
86
1757241
        new_context = current_context - 1;
87
88
        /* check for exceeding our maximum stack depth */
89
1757241
        if (new_context < _gx_system_draw_context_stack)
90
        {
91
70
            _gx_system_error_process(GX_DRAW_NESTING_EXCEEDED);
92
70
            return GX_DRAW_NESTING_EXCEEDED;
93
        }
94
    }
95
    else
96
    {
97
124950
        new_context = _gx_system_draw_context_stack_end - 1;
98
    }
99
100
101
    /* test to see if we have draw to this canvas since last refresh */
102
103
1882121
    if (canvas -> gx_canvas_draw_count > 0)
104
    {
105
1759632
        _gx_utility_rectangle_combine(&canvas -> gx_canvas_dirty_area, dirty_area);
106
    }
107
    else
108
    {
109
        /* initialize the dirty rectangle */
110
122489
        canvas -> gx_canvas_dirty_area = *dirty_area;
111
112
#ifdef GX_ENABLE_CANVAS_PARTIAL_FRAME_BUFFER
113
        if (canvas -> gx_canvas_status & GX_CANVAS_PARTIAL_FRAME_BUFFER)
114
        {
115
            canvas -> gx_canvas_memory_width = (GX_VALUE)(dirty_area -> gx_rectangle_right - dirty_area -> gx_rectangle_left + 1);
116
            canvas -> gx_canvas_memory_width = (GX_VALUE)((canvas -> gx_canvas_memory_width + 3) & 0xFFFC);
117
            canvas -> gx_canvas_memory_height = (GX_VALUE)(canvas -> gx_canvas_memory_size / display -> gx_display_driver_row_pitch_get((USHORT)canvas -> gx_canvas_memory_width));
118
            if (canvas -> gx_canvas_memory_height < (dirty_area -> gx_rectangle_bottom - dirty_area -> gx_rectangle_top + 1))
119
            {
120
                return GX_INVALID_MEMORY_SIZE;
121
            }
122
            canvas -> gx_canvas_memory_offset_x = dirty_area -> gx_rectangle_left;
123
            canvas -> gx_canvas_memory_offset_y = dirty_area -> gx_rectangle_top;
124
        }
125
#endif
126
    }
127
128
    /* Are we nested?  */
129

1882121
    if (canvas -> gx_canvas_draw_nesting > 0 && current_context)
130
    {
131
        /* Yes, clone the previous context.  */
132
1756619
        *new_context =  *current_context;
133
    }
134
    else
135
    {
136
        /* initialize the new context's brush */
137
125502
        _gx_context_brush_default(new_context);
138
139
        /* save the canvas pointer for any function that needs it */
140
125502
        new_context -> gx_draw_context_canvas = canvas;
141
142
        /* copy some canvas params to the context to speed access by drawing APIs */
143
144
125502
        new_context -> gx_draw_context_display = canvas -> gx_canvas_display;
145
125502
        new_context -> gx_draw_context_memory  = canvas -> gx_canvas_memory;
146
147
125502
        if (new_context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_NONE ||
148
20000
            new_context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_FLIP)
149
        {
150
#ifdef GX_ENABLE_CANVAS_PARTIAL_FRAME_BUFFER
151
            if (canvas -> gx_canvas_status & GX_CANVAS_PARTIAL_FRAME_BUFFER)
152
            {
153
                new_context -> gx_draw_context_pitch = canvas -> gx_canvas_memory_width;
154
                new_context -> gx_draw_context_offset_x = canvas -> gx_canvas_memory_offset_x;
155
                new_context -> gx_draw_context_offset_y = canvas -> gx_canvas_memory_offset_y;
156
            }
157
            else
158
            {
159
                new_context -> gx_draw_context_pitch = canvas -> gx_canvas_x_resolution;
160
                new_context -> gx_draw_context_offset_x = 0;
161
                new_context -> gx_draw_context_offset_y = 0;
162
            }
163
164
#else
165
105515
            new_context -> gx_draw_context_pitch = canvas -> gx_canvas_x_resolution;
166
#endif
167
        }
168
        else
169
        {
170
19987
            new_context -> gx_draw_context_pitch = canvas -> gx_canvas_y_resolution;
171
        }
172
    }
173
174
    /* Update canvas draw count and draw nesting.  */
175
176
1882121
    canvas -> gx_canvas_draw_nesting++;
177
1882121
    canvas -> gx_canvas_draw_count++;
178
179
    /* let display driver know if it has notification function */
180
1882121
    if (display -> gx_display_driver_drawing_initiate)
181
    {
182
1
        display -> gx_display_driver_drawing_initiate(display, canvas);
183
    }
184
185
    /* Update the draw context clipping rectangle.  */
186
1882121
    if (who)
187
    {
188
1881568
        _gx_utility_rectangle_overlap_detect(dirty_area,
189
                                             &who -> gx_widget_clip, &new_context -> gx_draw_context_dirty);
190
#if defined(GX_BRUSH_ALPHA_SUPPORT)
191
1881568
        if (who -> gx_widget_style & GX_STYLE_USE_LOCAL_ALPHA)
192
        {
193
26559
            new_context -> gx_draw_context_brush.gx_brush_alpha = who -> gx_widget_alpha;
194
        }
195
#endif
196
    }
197
    else
198
    {
199
553
        new_context -> gx_draw_context_dirty = *dirty_area;
200
    }
201
202
    /* initialize viewports to NULL */
203
1882121
    new_context -> gx_draw_context_view_head = GX_NULL;
204
205
206
    /* pick up the viewport list */
207
208
1882121
    if (canvas -> gx_canvas_status & GX_CANVAS_SIMPLE)
209
    {
210
555
        new_context -> gx_draw_context_simple_view.gx_view_next = NULL;
211
555
        new_context -> gx_draw_context_simple_view.gx_view_rectangle = new_context -> gx_draw_context_dirty;
212
555
        new_context -> gx_draw_context_view_head = &new_context -> gx_draw_context_simple_view;
213
    }
214
    else
215
    {
216
1881566
        if (who)
217
        {
218
            /* is the root window trying to draw */
219
1881565
            if (who -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
220
            {
221
206124
                win = (GX_WINDOW *)who;
222
206124
                new_context -> gx_draw_context_view_head = win -> gx_window_views;
223
            }
224
            else
225
            {
226
3433536
                while (who -> gx_widget_parent)
227
                {
228
3433535
                    if (who -> gx_widget_parent -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
229
                    {
230
1675440
                        if (who -> gx_widget_type >= GX_TYPE_WINDOW &&
231
1671852
                            !(who -> gx_widget_status & GX_STATUS_TRANSPARENT))
232
                        {
233
                            /* child windows of the root window get their own view list */
234
1622586
                            win = (GX_WINDOW *)who;
235
                        }
236
                        else
237
                        {
238
                            /* other widget types just inherit the view list of the root */
239
52854
                            win = (GX_WINDOW *)who -> gx_widget_parent;
240
                        }
241
1675440
                        new_context -> gx_draw_context_view_head = win -> gx_window_views;
242
1675440
                        break;
243
                    }
244
1758095
                    who = who -> gx_widget_parent;
245
                }
246
            }
247
248
            /* the widget being drawn is no longer marked dirty */
249
1881565
            who -> gx_widget_status &= ~GX_STATUS_DIRTY;
250
        }
251
    }
252
253
    /* the new context becomes the current context */
254
1882121
    _gx_system_current_draw_context = new_context;
255
256
1882121
    if (new_context -> gx_draw_context_view_head == GX_NULL)
257
    {
258
        /* no viewports for the caller */
259
94247
        return(GX_NO_VIEWS);
260
    }
261
1787874
    return(GX_SUCCESS);
262
}
263