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_system.h"
29 #include "gx_display.h"
30 
31 #if defined(GX_ARC_DRAWING_SUPPORT)
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _gx_display_driver_generic_rotated_ellipse_fill     PORTABLE C      */
38 /*                                                           6.1.6        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Kenneth Maxwell, Microsoft Corporation                              */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    Display driver to draw a filled ellipse.                            */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    context                               Drawing context               */
50 /*    xcenter                               x-coord of center of ellipse  */
51 /*    ycenter                               y-coord of center of ellipse  */
52 /*    a                                     Length of the Semi-major Axis */
53 /*    b                                     Length of the Semi-minor Axis */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    [gx_display_driver_horizontal_line_draw]                            */
62 /*                                          Basic display driver          */
63 /*                                            horizontal line draw routine*/
64 /*    [gx_display_driver_horizontal_pixelmap_line_draw]                   */
65 /*                                          Basic display driver          */
66 /*                                            horizontal pixelmap line    */
67 /*                                            draw function               */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    GUIX Internal Code                                                  */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  12-31-2020     Kenneth Maxwell          Initial Version 6.1.3         */
78 /*  04-02-2021     Ting Zhu                 Modified comment(s),          */
79 /*                                            modified algorithm to make  */
80 /*                                            it fit one-width antialiaed */
81 /*                                            ellipse outline,            */
82 /*                                            resulting in version 6.1.6  */
83 /*                                                                        */
84 /**************************************************************************/
_gx_display_driver_generic_rotated_ellipse_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,INT a,INT b)85 VOID _gx_display_driver_generic_rotated_ellipse_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, INT a, INT b)
86 {
87 /* The ellipse fill function follows Bresenham ellipse algorithm while
88    connecting the two point that symmetric with respect to y-axis. */
89 
90 GX_DISPLAY           *display;
91 GX_RECTANGLE         *clip;
92 GX_BRUSH             *brush;
93 INT                   x1;
94 INT                   x;
95 INT                   y;
96 INT                   y0;
97 INT                   y1;
98 INT                   sign[2] = {1, -1};
99 INT                  *pLineEnds;
100 INT                   index;
101 INT                   width;
102 INT                   Index;
103 INT                   aa;
104 INT                   bb;
105 INT                   ypos;
106 INT                   xmin;
107 INT                   xmax;
108 INT                   skip_line;
109 GX_PIXELMAP          *pixelmap = GX_NULL;
110 GX_COLOR              fill_color;
111 GX_FILL_PIXELMAP_INFO info;
112 GX_BYTE               xsign;
113 INT                   error;
114 INT                   realval;
115 GX_BOOL               record;
116 
117     display = context -> gx_draw_context_display;
118     clip = context -> gx_draw_context_clip;
119     brush = &context -> gx_draw_context_brush;
120 
121     if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
122     {
123         if (brush -> gx_brush_pixelmap == GX_NULL)
124         {
125             /* Nothing should be drawn if pixelmap isn't set with GX_BRUSH_PIXELMAP_FILL style. */
126             return;
127         }
128 
129         pixelmap = brush -> gx_brush_pixelmap;
130 
131         if (pixelmap -> gx_pixelmap_format != display -> gx_display_color_format)
132         {
133             /* Display driver only support its native format pixelmap.*/
134             /* Nothing should be drawn if pixelmap format isn't support. */
135             return;
136         }
137 
138         memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
139 
140         info.pixelmap = brush -> gx_brush_pixelmap;
141         info.current_pixel_ptr = (GX_UBYTE *)info.pixelmap -> gx_pixelmap_data;
142 
143         if (pixelmap -> gx_pixelmap_aux_data_size)
144         {
145             info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
146         }
147     }
148 
149     xmin = xcenter - a;
150     xmax = xcenter + a;
151 
152     /* Calculate minimum y line. */
153     if (clip -> gx_rectangle_left > xmin)
154     {
155         xmin = clip -> gx_rectangle_left;
156     }
157 
158     /* Calculate maximum y line. */
159     if (clip -> gx_rectangle_right < xmax)
160     {
161         xmax = clip -> gx_rectangle_right;
162     }
163 
164     width = (xmax - xmin + 1);
165     pLineEnds = _gx_system_scratchpad;
166 
167     /* default the point array to being off the screen on both sides: */
168     for (Index = 0; Index < width * 2; Index += 2)
169     {
170         pLineEnds[Index] = 2000;
171         pLineEnds[Index + 1] = 0;
172     }
173 
174     aa = a * a;
175     bb = b * b;
176     x = 0;
177     y = b;
178     error = 0;
179 
180     /* Region I of the first quarter of the ellipse.  */
181     while (2 * bb * (x + 1) < aa * (2 * y - 1))
182     {
183         /* calculate error of next pixel. */
184         realval = bb - bb * (x + 1) * (x + 1) / aa;
185         error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3);
186 
187         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             realval = bb - bb * x * x / aa;
192             error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3);
193             break;
194         }
195 
196         y0 = ycenter - (y - 1);
197         y1 = ycenter + (y - 1);
198 
199         if (y0 < clip -> gx_rectangle_top)
200         {
201             y0 = clip -> gx_rectangle_top;
202         }
203 
204         if (y1 > clip -> gx_rectangle_bottom)
205         {
206             y1 = clip -> gx_rectangle_bottom;
207         }
208 
209         for (index = 0; index < 2; index++)
210         {
211             x1 = x * sign[index] + xcenter;
212 
213             if ((x1 >= xmin) && (x1 <= xmax))
214             {
215                 Index = (x1 - xmin) << 1;
216                 pLineEnds[Index] = y0;
217                 pLineEnds[Index + 1] = y1;
218             }
219         }
220 
221         if (error >= 255)
222         {
223             y--;
224         }
225 
226         x++;
227     }
228 
229     record = GX_TRUE;
230 
231     y0 = ycenter - y;
232     y1 = ycenter + y;
233 
234     if (y0 < clip -> gx_rectangle_top)
235     {
236         y0 = clip -> gx_rectangle_top;
237     }
238 
239     if (y1 > clip -> gx_rectangle_bottom)
240     {
241         y1 = clip -> gx_rectangle_bottom;
242     }
243 
244     for (index = 0; index < 2; index++)
245     {
246         x1 = x * sign[index] + xcenter;
247 
248         if ((x1 >= xmin) && (x1 <= xmax))
249         {
250             Index = (x1 - xmin) << 1;
251             pLineEnds[Index] = y0;
252             pLineEnds[Index + 1] = y1;
253         }
254     }
255 
256     /* Region II of the first quarter of the ellipse.  */
257     while (y > 0)
258     {
259         y--;
260 
261         realval = aa - aa * y * y / bb;
262         error = (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3) - (x << 8);
263 
264         while (error >= 255)
265         {
266             error -= 255;
267             x++;
268 
269             record = GX_TRUE;
270         }
271 
272         if (record)
273         {
274             record = GX_FALSE;
275 
276             y0 = ycenter - y;
277             y1 = ycenter + y;
278 
279             if (y0 < clip -> gx_rectangle_top)
280             {
281                 y0 = clip -> gx_rectangle_top;
282             }
283 
284             if (y1 > clip -> gx_rectangle_bottom)
285             {
286                 y1 = clip -> gx_rectangle_bottom;
287             }
288 
289             for (index = 0; index < 2; index++)
290             {
291                 x1 = x * sign[index] + xcenter;
292 
293                 if ((x1 >= xmin) && (x1 <= xmax))
294                 {
295                     Index = (x1 - xmin) << 1;
296                     pLineEnds[Index] = y0;
297                     pLineEnds[Index + 1] = y1;
298                 }
299             }
300         }
301     }
302 
303     if (pixelmap != GX_NULL)
304     {
305         if (context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_CW)
306         {
307             skip_line = (xmax - (xcenter - a) + 1) % pixelmap -> gx_pixelmap_width;
308 
309             if (skip_line)
310             {
311                 skip_line = pixelmap -> gx_pixelmap_width - skip_line;
312             }
313 
314             x1 = xmax;
315             xsign = -1;
316             Index = (width - 1) * 2;
317         }
318         else
319         {
320             skip_line = (xmin - clip -> gx_rectangle_left);
321 
322             x1 = xmin;
323             xsign = 1;
324             Index = 0;
325         }
326 
327         if (skip_line)
328         {
329             info.draw = GX_FALSE;
330             while (skip_line--)
331             {
332                 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, 0, &info);
333             }
334         }
335 
336         info.draw = GX_TRUE;
337         ypos = ycenter - b;
338 
339         for (x = xmin; x <= xmax; x++)
340         {
341             info.x_offset = pLineEnds[Index] - ypos;
342             display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], x1, &info);
343 
344             x1 += xsign;
345             Index += xsign;
346             Index += xsign;
347         }
348     }
349     else
350     {
351         Index = 0;
352         fill_color = brush -> gx_brush_fill_color;
353 
354         for (x = xmin; x <= xmax; x++)
355         {
356             display -> gx_display_driver_vertical_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], x, 1, fill_color);
357             Index += 2;
358         }
359     }
360 }
361 #endif
362 
363