GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_aliased_wide_ellipse_draw.c Lines: 104 104 100.0 %
Date: 2026-03-06 19:21:09 Branches: 68 68 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
#include "gx_system.h"
31
32
#if defined(GX_ARC_DRAWING_SUPPORT)
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _gx_display_driver_generic_aliased_wide_ellipse_draw                */
38
/*                                                        PORTABLE C      */
39
/*                                                           6.1          */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Kenneth Maxwell, Microsoft Corporation                              */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    Display driver function to draw anti-aliased ellipse with wide      */
47
/*    outline.                                                            */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    context                               Drawing context               */
52
/*    xcenter                               x-coord of center of ellipse  */
53
/*    ycenter                               y-coord of center of ellipse  */
54
/*    a                                     Length of the Semi-major Axis */
55
/*    b                                     Length of the Semi-minor Axis */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    None                                                                */
60
/*                                                                        */
61
/*  CALLS                                                                 */
62
/*                                                                        */
63
/*    [gx_display_driver_pixel_blend]       Basic display driver pixel    */
64
/*                                            blend function              */
65
/*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
66
/*                                            inside rectangle            */
67
/*    _gx_utility_math_sqrt                 Compute the square root value */
68
/*    [gx_display_driver_horizontal_line_draw]                            */
69
/*                                          Basic display driver          */
70
/*                                            horizontal line draw routine*/
71
/*                                                                        */
72
/*  CALLED BY                                                             */
73
/*                                                                        */
74
/*    GUIX Internal Code                                                  */
75
/*                                                                        */
76
/**************************************************************************/
77
931
VOID _gx_display_driver_generic_aliased_wide_ellipse_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, INT a, INT b)
78
{
79
GX_DISPLAY   *display;
80
GX_RECTANGLE *clip;
81
GX_BRUSH     *brush;
82
INT           x;
83
INT           x2;
84
INT           y;
85
INT           y2;
86
GX_POINT      point;
87
931
INT           sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
88
INT           index;
89
INT           aa;
90
INT           bb;
91
INT          *pLineEnds;
92
INT           ymin;
93
INT           ymax;
94
INT           height;
95
INT           error;
96
INT           loop;
97
INT           brush_width;
98
GX_UBYTE      alpha1;
99
GX_UBYTE      alpha2;
100
101
VOID          (*blend_func)(GX_DRAW_CONTEXT *context,
102
                            INT x, INT y, GX_COLOR color, GX_UBYTE error);
103
104
#if defined(GX_BRUSH_ALPHA_SUPPORT)
105
GX_UBYTE old_alpha;
106
107
931
    old_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
108
931
    context -> gx_draw_context_brush.gx_brush_alpha = GX_ALPHA_VALUE_OPAQUE;
109
#endif
110
931
    display = context -> gx_draw_context_display;
111
931
    blend_func = display -> gx_display_driver_pixel_blend;
112
113
931
    if (blend_func == GX_NULL)
114
    {
115
32
        return;
116
    }
117
930
    clip = context -> gx_draw_context_clip;
118
930
    brush = &context -> gx_draw_context_brush;
119
930
    brush_width = brush -> gx_brush_width;
120
121
930
    if ((a <= ((brush_width - 1) >> 1)) ||
122
900
        (b <= ((brush_width - 1) >> 1)))
123
    {
124
31
        return;
125
    }
126
127
899
    ymin = ycenter - b - (brush_width >> 1);
128
899
    ymax = ycenter + b + (brush_width >> 1);
129
130
899
    if (ymin < clip -> gx_rectangle_top)
131
    {
132
56
        ymin = clip -> gx_rectangle_top;
133
    }
134
135
899
    if (ymax > clip -> gx_rectangle_bottom)
136
    {
137
2
        ymax = clip -> gx_rectangle_bottom;
138
    }
139
140
899
    height = ymax - ymin + 1;
141
899
    pLineEnds = _gx_system_scratchpad;
142
143
402316
    for (y = 0; y <= height * 2; y++)
144
    {
145
401417
        pLineEnds[y] = 0;
146
    }
147
148
    /* loop = 0: draw inner ellipse, and save point array.
149
       loop = 1: draw outer ellipse, and save point array. */
150
2697
    for (loop = 0; loop < 2; loop++)
151
    {
152
1798
        if (loop == 0)
153
        {
154
899
            a -= ((brush_width - 1) >> 1);
155
899
            b -= ((brush_width - 1) >> 1);
156
        }
157
        else
158
        {
159
899
            a += brush_width - 1;
160
899
            b += brush_width - 1;
161
        }
162
163
1798
        aa = a * a;
164
1798
        bb = b * b;
165
1798
        x = 0;
166
1798
        y = b;
167
1798
        error = 0;
168
169
        /* Region I of the first quarter of the ellipse.  */
170
154939
        while (2 * bb * (x + 1) < aa * (2 * y - 1))
171
        {
172
153159
            alpha1 = (GX_UBYTE)(255 - error);
173
153159
            alpha2 = (GX_UBYTE)error;
174
175
            /* error is the distance between mathmatic point to
176
               drawing point, which is used to do pixel blending.  */
177
153159
            y2 = bb - bb * (x + 1) * (x + 1) / aa;
178
153159
            error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(y2 << 10)) << 3);
179
180
153159
            if (error >= 510)
181
            {
182
                /* The slope in point(x + 1, y) is greater than -1,
183
                   make point(x, y) the delimit pixel, break here. */
184
18
                y2 = bb - bb * x * x / aa;
185
18
                error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(y2 << 10)) << 3);
186
18
                break;
187
            }
188
189
765705
            for (index = 0; index < 4; index++)
190
            {
191
612564
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
192
612564
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
193
194
612564
                if (_gx_utility_rectangle_point_detect(clip, point))
195
                {
196
                    /* Draw point(x, y).  */
197
609750
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
198
                }
199
200
612564
                point.gx_point_y = (GX_VALUE)((y - 1) * sign[index][1] + ycenter);
201
202
612564
                if (_gx_utility_rectangle_point_detect(clip, point))
203
                {
204
                    /* Draw point(x, y - 1).  */
205
610422
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha2);
206
                }
207
            }
208
209
210
153141
            if (error >= 255)
211
            {
212
52305
                error -= 255;
213
52305
                y--;
214
215
156915
                for (index = 0; index < 2; index++)
216
                {
217
104610
                    y2 = y * sign[index][0] + ycenter;
218
219

104610
                    if ((y2 >= ymin) && (y2 <= ymax))
220
                    {
221
104374
                        if (loop == 0)
222
                        {
223
                            /* Inner circle points.  */
224
50442
                            pLineEnds[(y2 - ymin) << 1] = x + 1;
225
                        }
226
                        else
227
                        {
228
                            /* Outer circle points.  */
229
53932
                            pLineEnds[((y2 - ymin) << 1) + 1] = x;
230
                        }
231
                    }
232
                }
233
            }
234
235
153141
            x++;
236
        }
237
238
        /* Draw delimit pixel where der*/
239
8990
        for (index = 0; index < 4; index++)
240
        {
241
7192
            point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
242
7192
            point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
243
244
7192
            if (_gx_utility_rectangle_point_detect(clip, point))
245
            {
246
7116
                blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, (GX_UBYTE)(255 - error));
247
            }
248
        }
249
250
        /* Region II of the first quarter of the ellipse.  */
251
143460
        while (y > 0)
252
        {
253
141662
            y--;
254
255
141662
            y2 = aa - aa * y * y / bb;
256
141662
            error = (INT)(_gx_utility_math_sqrt((UINT)(y2 << 10)) << 3) - (x << 8);
257
258
190268
            while (error >= 255)
259
            {
260
48606
                error -= 255;
261
48606
                x++;
262
            }
263
264
141662
            alpha1 = (GX_UBYTE)(255 - error);
265
141662
            alpha2 = (GX_UBYTE)error;
266
267
424986
            for (index = 0; index < 2; index++)
268
            {
269
283324
                y2 = y * sign[index][0] + ycenter;
270
271

283324
                if ((y2 >= ymin) && (y2 <= ymax))
272
                {
273
282642
                    if (loop == 0)
274
                    {
275
                        /* Inner circle points.  */
276
137156
                        pLineEnds[(y2 - ymin) << 1] = x + 1;
277
                    }
278
                    else
279
                    {
280
                        /* Outer circle points.  */
281
145486
                        pLineEnds[((y2 - ymin) << 1) + 1] = x;
282
                    }
283
                }
284
            }
285
286
708310
            for (index = 0; index < 4; index++)
287
            {
288
566648
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
289
566648
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
290
291
566648
                if (_gx_utility_rectangle_point_detect(clip, point))
292
                {
293
                    /* Draw point(x, y). */
294
550452
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
295
                }
296
297
566648
                point.gx_point_x = (GX_VALUE)((x + 1) * sign[index][0] + xcenter);
298
299
566648
                if (_gx_utility_rectangle_point_detect(clip, point))
300
                {
301
                    /* Draw point(x + 1, y). */
302
545980
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha2);
303
                }
304
            }
305
        }
306
    }
307
308
899
    index = 0;
309
310
    /* Filling outlines with horizontal line. */
311
201158
    for (y = ymin; y <= ymax; y++)
312
    {
313
600777
        for (loop = 0; loop < 2; loop++)
314
        {
315
400518
            x = pLineEnds[index] * sign[loop][0] + xcenter;
316
400518
            x2 = pLineEnds[index + 1] * sign[loop][0] + xcenter;
317
318
400518
            if (x > x2)
319
            {
320
172478
                GX_SWAP_VALS(x, x2);
321
            }
322
323
400518
            if (x < clip -> gx_rectangle_left)
324
            {
325
2920
                x = clip -> gx_rectangle_left;
326
            }
327
328
400518
            if (x2 > clip -> gx_rectangle_right)
329
            {
330
8308
                x2 = clip -> gx_rectangle_right;
331
            }
332
333
400518
            display -> gx_display_driver_horizontal_line_draw(context, x, x2, y, 1,
334
                                                              brush -> gx_brush_line_color);
335
        }
336
337
200259
        index += 2;
338
    }
339
340
#if defined(GX_BRUSH_ALPHA_SUPPORT)
341
899
    context -> gx_draw_context_brush.gx_brush_alpha = old_alpha;
342
#endif
343
}
344
#endif
345