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

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

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