GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_ellipse_draw.c Lines: 62 62 100.0 %
Date: 2026-03-06 19:21:09 Branches: 38 38 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
/**   Display Management (Display)                                        */
19
/**                                                                       */
20
/**************************************************************************/
21
22
#define GX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "gx_api.h"
28
#include "gx_utility.h"
29
#include "gx_display.h"
30
31
/**************************************************************************/
32
/*                                                                        */
33
/*  FUNCTION                                               RELEASE        */
34
/*                                                                        */
35
/*    _gx_display_driver_generic_ellipse_draw             PORTABLE C      */
36
/*                                                           6.1.6        */
37
/*  AUTHOR                                                                */
38
/*                                                                        */
39
/*    Kenneth Maxwell, Microsoft Corporation                              */
40
/*                                                                        */
41
/*  DESCRIPTION                                                           */
42
/*                                                                        */
43
/*    Display driver to draw ellipse.                                     */
44
/*                                                                        */
45
/*  INPUT                                                                 */
46
/*                                                                        */
47
/*    context                               Drawing context               */
48
/*    xcenter                               x-coord of center of ellipse  */
49
/*    ycenter                               y-coord of center of ellipse  */
50
/*    a                                     Length of the Semi-major Axis */
51
/*    b                                     Length of the Semi-minor Axis */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    None                                                                */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    [gx_display_driver_pixel_blend]       Basic display driver pixel    */
60
/*                                            blend function              */
61
/*    [gx_display_driver_pixel_write]       Basic display driver pixel    */
62
/*                                            write function              */
63
/*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
64
/*                                            inside rectangle            */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    GUIX Internal Code                                                  */
69
/*                                                                        */
70
/**************************************************************************/
71
432
VOID _gx_display_driver_generic_ellipse_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, INT a, INT b)
72
{
73
/* The ellipse draw function is implemented from Bresenham ellipse algorithm. */
74
INT           x;
75
INT           y;
76
INT           d;
77
GX_POINT      point;
78
432
INT           sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
79
INT           index;
80
INT           aa;
81
INT           bb;
82
432
GX_DISPLAY   *display = context -> gx_draw_context_display;
83
432
GX_BRUSH     *brush = &context -> gx_draw_context_brush;
84
432
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
85
86
#if defined(GX_BRUSH_ALPHA_SUPPORT)
87
432
GX_UBYTE brush_alpha = brush -> gx_brush_alpha;
88
89
432
    if (display -> gx_display_driver_pixel_blend == GX_NULL)
90
    {
91
        /* Pixel blend function is null means alpha isn't supported in this driver.
92
           So set alpha value to 0xff to make it draw the original color in case GX_BRUSH_ALPHA_SUPPORT is defined. */
93
60
        brush_alpha = 0xff;
94
    }
95
    else
96
    {
97
372
        if (brush_alpha == 0)
98
        {
99
            /* Nothing to draw here. */
100
124
            return;
101
        }
102
    }
103
#endif
104
105
    /* The ellipse is split into 2 regions, region I with dx > dy and resion II with dx <= dy.
106
       In region I, the midpoint between (x + 1, y) and (x + 1, y - 1) is used to select next point that is closer to the ellipse,
107
       d(x + 1, y - 0.5) is the distance from the midpoint to the ellipse center,
108
       if the decision < 0, the midpoint is inside the ellipse, point (x + 1, y - 1) is closer to the ellipse, and be selected for drawing.
109
       otherwise, (x + 1, y) is selected.
110
       In region II, the midpoint between (x, y - 1) and (x + 1, y - 1) is used to select next point that is closer to the ellipse,
111
       d(x + 0.5, y - 1) is the distance from the midpoint to ellipse center,
112
       if the decision < 0, the midpoint is inside the ellipse, point(x + 1, y - 1) is closer to the ellipse, and be selected for drawing,
113
       otherwise, (x, y - 1) is selected.
114
115
       Ellipse equation is f(x, y) = sqr(b * x) + sqr(a * y) - sqr(a * b).
116
       First, we assume ellipse is centered at the origin(0, 0), and the first point is (0, b).
117
       Set initial decision value for region I as d = f(1, b - 0.5) = sqr(b) + sqr(a) * (-b + 0.25).
118
    */
119
120
308
    aa = a * a;
121
308
    bb = b * b;
122
308
    x = 0;
123
308
    y = b;
124
125
    /* Decision is enlarged by 4 to avoid floating point. */
126
308
    d = (bb << 2) + aa * (1 - (b << 2));
127
128
#if defined(GX_BRUSH_ALPHA_SUPPORT)
129
308
    if (brush_alpha != 0xff)
130
    {
131
132
        /* Region I of the first quarter of the ellipse.  */
133
8646
        while ((bb << 1) * (x + 1) < aa * (2 * y - 1))
134
        {
135
42610
            for (index = 0; index < 4; index++)
136
            {
137
34088
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
138
34088
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
139
140
34088
                if (_gx_utility_rectangle_point_detect(clip, point))
141
                {
142
34056
                    display -> gx_display_driver_pixel_blend(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, brush_alpha);
143
                }
144
            }
145
146
8522
            if (d < 0)
147
            {
148
6402
                d += (bb << 2) * ((x << 1) + 3);
149
            }
150
            else
151
            {
152
2120
                d += (bb << 2) * ((x << 1) + 3) + (aa << 3) * (1 - y);
153
2120
                y--;
154
            }
155
8522
            x++;
156
        }
157
158
124
        d = bb * ((x << 1) + 1) * ((x << 1) + 1) + (aa << 2) * (y - 1) * (y - 1) - (aa << 2) * bb;
159
160
        /* Region II of the first quarter of the ellipse.  */
161
8828
        while (y >= 0)
162
        {
163
43520
            for (index = 0; index < 4; index++)
164
            {
165
34816
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
166
34816
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
167
168
34816
                if (_gx_utility_rectangle_point_detect(clip, point))
169
                {
170
34220
                    display -> gx_display_driver_pixel_blend(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, brush_alpha);
171
                }
172
            }
173
174
8704
            if (d < 0)
175
            {
176
2178
                d += (bb << 3) * (x + 1) + (aa << 2) * (3 - (y << 1));
177
2178
                x++;
178
            }
179
            else
180
            {
181
6526
                d += (aa << 2) * (3 - (y << 1));
182
            }
183
184
8704
            y--;
185
        }
186
    }
187
    else
188
    {
189
#endif
190
        /* Region I of the first quarter of the ellipse.  */
191
10426
        while ((bb << 1) * (x + 1) < aa * (2 * y - 1))
192
        {
193
51210
            for (index = 0; index < 4; index++)
194
            {
195
40968
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
196
40968
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
197
198
40968
                if (_gx_utility_rectangle_point_detect(clip, point))
199
                {
200
40936
                    display -> gx_display_driver_pixel_write(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color);
201
                }
202
            }
203
204
10242
            if (d < 0)
205
            {
206
7582
                d += (bb << 2) * ((x << 1) + 3);
207
            }
208
            else
209
            {
210
2660
                d += (bb << 2) * ((x << 1) + 3) + (aa << 3) * (1 - y);
211
2660
                y--;
212
            }
213
10242
            x++;
214
        }
215
216
        /* Set initial decision value for region II as d = f(x + 0.5, y - 1) = sqr(b * (x + 0.5) + sqr(a * (y - 1)) - sqr(a * b).
217
           Enlarge the decision by 4 to avoid float calculation. */
218
219
184
        d = bb * ((x << 1) + 1) * ((x << 1) + 1) + (aa << 2) * (y - 1) * (y - 1) - (aa << 2) * bb;
220
221
        /* Region II of the first quarter of the ellipse.  */
222
12128
        while (y >= 0)
223
        {
224
59720
            for (index = 0; index < 4; index++)
225
            {
226
47776
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
227
47776
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
228
229
47776
                if (_gx_utility_rectangle_point_detect(clip, point))
230
                {
231
47180
                    display -> gx_display_driver_pixel_write(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color);
232
                }
233
            }
234
235
11944
            if (d < 0)
236
            {
237
2738
                d += (bb << 3) * (x + 1) + (aa << 2) * (3 - (y << 1));
238
2738
                x++;
239
            }
240
            else
241
            {
242
9206
                d += (aa << 2) * (3 - (y << 1));
243
            }
244
245
11944
            y--;
246
        }
247
#if defined(GX_BRUSH_ALPHA_SUPPORT)
248
    }
249
#endif
250
}
251