GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_aliased_wide_circle_draw.c Lines: 86 86 100.0 %
Date: 2024-12-05 08:52:37 Branches: 54 54 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
/**   Display Management (Display)                                        */
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_utility.h"
29
#include "gx_display.h"
30
31
/**************************************************************************/
32
/*                                                                        */
33
/*  FUNCTION                                               RELEASE        */
34
/*                                                                        */
35
/*    _gx_display_driver_generic_aliased_wide_circle_draw PORTABLE C      */
36
/*                                                           6.1.7        */
37
/*  AUTHOR                                                                */
38
/*                                                                        */
39
/*    Kenneth Maxwell, Microsoft Corporation                              */
40
/*                                                                        */
41
/*  DESCRIPTION                                                           */
42
/*                                                                        */
43
/*    Display driver function to draw anti-aliased circle with            */
44
/*    specified outline width.                                            */
45
/*                                                                        */
46
/*  INPUT                                                                 */
47
/*                                                                        */
48
/*    context                               Drawing context               */
49
/*    xcenter                               x-coord of center of circle   */
50
/*    ycenter                               y-coord of center of circle   */
51
/*    r                                     Radius of circle              */
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_utility_rectangle_point_detect    Detect whether a pixel is     */
62
/*                                            inside rectangle            */
63
/*    [gx_display_driver_horizontal_line_draw]                            */
64
/*                                          Basic display driver          */
65
/*                                            horizontal line draw routine*/
66
/*                                                                        */
67
/*  CALLED BY                                                             */
68
/*                                                                        */
69
/*    GUIX Internal Code                                                  */
70
/*                                                                        */
71
/*  RELEASE HISTORY                                                       */
72
/*                                                                        */
73
/*    DATE              NAME                      DESCRIPTION             */
74
/*                                                                        */
75
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
76
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
77
/*                                            resulting in version 6.1    */
78
/*  06-02-2021     Ting Zhu                 Modified comment(s),          */
79
/*                                            fixed compile warnings,     */
80
/*                                            resulting in version 6.1.7  */
81
/*                                                                        */
82
/**************************************************************************/
83
#if defined(GX_ARC_DRAWING_SUPPORT)
84
4049
VOID _gx_display_driver_generic_aliased_wide_circle_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r)
85
{
86
/* The circle draw function is implemented from midpoint circle algorithm. */
87
88
GX_DISPLAY   *display;
89
GX_RECTANGLE *clip;
90
GX_BRUSH     *brush;
91
INT           brush_width;
92
4049
INT           x = 0;
93
INT           x2;
94
INT           y;
95
INT           y2;
96
GX_POINT      point;
97
4049
INT           sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
98
INT           index;
99
4049
INT           error = 0;
100
INT           loop;
101
INT          *pLineEnds;
102
INT           ymin;
103
INT           ymax;
104
INT           height;
105
GX_UBYTE      alpha1;
106
GX_UBYTE      alpha2;
107
VOID          (*blend_func)(GX_DRAW_CONTEXT *context,
108
                            INT x, INT y, GX_COLOR color, GX_UBYTE error);
109
110
#if defined(GX_BRUSH_ALPHA_SUPPORT)
111
GX_UBYTE temp_alpha;
112
4049
    temp_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
113
4049
    context -> gx_draw_context_brush.gx_brush_alpha = GX_ALPHA_VALUE_OPAQUE;
114
#endif
115
116
4049
    display = context -> gx_draw_context_display;
117
4049
    clip = context -> gx_draw_context_clip;
118
4049
    brush = &context -> gx_draw_context_brush;
119
4049
    brush_width = brush -> gx_brush_width;
120
121
4049
    if (r <= (UINT)((brush_width - 1) >> 1))
122
    {
123
199
        return;
124
    }
125
126
3851
    blend_func = display -> gx_display_driver_pixel_blend;
127
128
3851
    if (blend_func == GX_NULL)
129
    {
130
1
        return;
131
    }
132
133
3850
    ymin = ycenter - (INT)r - (brush_width >> 1);
134
3850
    ymax = ycenter + (INT)r + (brush_width >> 1);
135
136
3850
    if (ymin < clip -> gx_rectangle_top)
137
    {
138
165
        ymin = clip -> gx_rectangle_top;
139
    }
140
141
3850
    if (ymax > clip -> gx_rectangle_bottom)
142
    {
143
243
        ymax = clip -> gx_rectangle_bottom;
144
    }
145
146
3850
    height = ymax - ymin + 1;
147
3850
    pLineEnds = _gx_system_scratchpad;
148
149
486687
    for (y = 0; y <= height * 2; y += 2)
150
    {
151
482837
        pLineEnds[y] = 0;
152
482837
        pLineEnds[y + 1] = 0;
153
    }
154
155
    /* loop = 0: draw inner circle, and save the point array.
156
       loop = 1: draw outer circle, and save the point array.  */
157
11550
    for (loop = 0; loop < 2; loop++)
158
    {
159
7700
        if (loop == 0)
160
        {
161
            /* Calculate the inner circle radius.  */
162
3850
            r = (UINT)(r - (UINT)((brush_width - 1) >> 1));
163
        }
164
        else
165
        {
166
            /* Calculate the outer circle radious.  */
167
3850
            r += (UINT)(brush_width - 1);
168
        }
169
170
7700
        x = 0;
171
7700
        y = (INT)r;
172
7700
        error = 0;
173
174
326873
        while (x < y)
175
        {
176
177
957519
            for (index = 0; index < 2; index++)
178
            {
179
638346
                x2 = y;
180
638346
                y2 = x * sign[index][0] + ycenter;
181
182

638346
                if ((y2 >= ymin) && (y2 <= ymax))
183
                {
184
638300
                    pLineEnds[((y2 - ymin) << 1) + loop] = x2 - loop;
185
                }
186
            }
187
188
319173
            alpha1 = (GX_UBYTE)(255 - error);
189
319173
            alpha2 = (GX_UBYTE)error;
190
191
1595865
            for (index = 0; index < 4; index++)
192
            {
193
1276692
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
194
1276692
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
195
196
1276692
                if (_gx_utility_rectangle_point_detect(clip, point))
197
                {
198
                    /* Draw point(x, y).  */
199
1181152
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
200
                }
201
202
1276692
                point.gx_point_y = (GX_VALUE)((y - 1) * sign[index][1] + ycenter);
203
204
1276692
                if (_gx_utility_rectangle_point_detect(clip, point))
205
                {
206
                    /* Draw point(x, y - 1). */
207
1188240
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, (GX_UBYTE)alpha2);
208
                }
209
210
1276692
                point.gx_point_x = (GX_VALUE)(y * sign[index][0] + xcenter);
211
1276692
                point.gx_point_y = (GX_VALUE)(x * sign[index][1] + ycenter);
212
213
1276692
                if (_gx_utility_rectangle_point_detect(clip, point))
214
                {
215
                    /* Draw point (y, x). */
216
1149504
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
217
                }
218
219
1276692
                point.gx_point_x = (GX_VALUE)((y - 1) * sign[index][0] + xcenter);
220
221
1276692
                if (_gx_utility_rectangle_point_detect(clip, point))
222
                {
223
                    /* Draw point (y - 1, x. )*/
224
1154196
                    blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha2);
225
                }
226
            }
227
228
319173
            x++;
229
230
319173
            y2 = (INT)(r * r) - x * x;
231
232
            /* error is the distance from mathmatical point to
233
               drawing point, which is used to determin alpha value.  */
234
319173
            error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(y2 << 10)) << 3);
235
236
449683
            while (error >= 255)
237
            {
238
130510
                error -= 255;
239
130510
                y--;
240
241
391530
                for (index = 0; index < 2; index++)
242
                {
243
261020
                    x2 = x;
244
261020
                    y2 = y * sign[index][0] + ycenter;
245
246

261020
                    if ((y2 >= ymin) && (y2 <= ymax))
247
                    {
248
249988
                        pLineEnds[((y2 - ymin) << 1) + loop] = x2 - loop;
249
                    }
250
                }
251
            }
252
        }
253
    }
254
255
19250
    for (index = 0; index < 4; index++)
256
    {
257
15400
        point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
258
15400
        point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
259
260
15400
        if (_gx_utility_rectangle_point_detect(clip, point))
261
        {
262
15396
            blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, (GX_UBYTE)(255 - error));
263
        }
264
    }
265
266
3850
    index = 0;
267
268
    /* Filling outlines with horizontal line. */
269
482837
    for (y = ymin; y <= ymax; y++)
270
    {
271
1436961
        for (loop = 0; loop < 2; loop++)
272
        {
273
957974
            x = pLineEnds[index] * sign[loop][0] + xcenter;
274
957974
            x2 = pLineEnds[index + 1] * sign[loop][0] + xcenter;
275
276
957974
            if (x > x2)
277
            {
278
444575
                GX_SWAP_VALS(x, x2);
279
            }
280
281
957974
            if (x < clip -> gx_rectangle_left)
282
            {
283
38232
                x = clip -> gx_rectangle_left;
284
            }
285
286
957974
            if (x2 > clip -> gx_rectangle_right)
287
            {
288
36180
                x2 = clip -> gx_rectangle_right;
289
            }
290
291
957974
            display -> gx_display_driver_horizontal_line_draw(context, x, x2, y, 1,
292
                                                              brush -> gx_brush_line_color);
293
        }
294
478987
        index += 2;
295
    }
296
297
#if defined(GX_BRUSH_ALPHA_SUPPORT)
298
3850
    context -> gx_draw_context_brush.gx_brush_alpha = temp_alpha;
299
#endif
300
}
301
#endif
302