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 #include "gx_canvas.h"
31 
32 #if defined(GX_ARC_DRAWING_SUPPORT)
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _gx_display_driver_generic_simple_aliased_wide_arc_draw             */
39 /*                                                        PORTABLE C      */
40 /*                                                           6.1          */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Kenneth Maxwell, Microsoft Corporation                              */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    Innner help function that draw an aliased wide arc between [90, 180]*/
48 /*     or [270, 540].                                                     */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    context                               Drawing context               */
53 /*    xcenter                               curx-coord of center of circle*/
54 /*    ycenter                               cury-coord of center of circle*/
55 /*    r                                     Radius of circle              */
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_display_driver_arc_clipping_get   Get an arc clipping.          */
66 /*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
67 /*                                            inside rectangle            */
68 /*    _gx_utility_circle_point_get          Get point coord on a circle   */
69 /*    [gx_display_driver_horizontal_line_draw]                            */
70 /*                                          Basic display driver          */
71 /*                                            horizontal line draw routine*/
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    _gx_display_driver_generic_aliased_wide_arc_draw                    */
76 /*                                                                        */
77 /*  RELEASE HISTORY                                                       */
78 /*                                                                        */
79 /*    DATE              NAME                      DESCRIPTION             */
80 /*                                                                        */
81 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
82 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
83 /*                                            resulting in version 6.1    */
84 /*                                                                        */
85 /**************************************************************************/
_gx_display_driver_generic_simple_aliased_wide_arc_draw(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle)86 static VOID _gx_display_driver_generic_simple_aliased_wide_arc_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
87 {
88 /* The function draw a wide arc between 90 and 270 or beween 270 and 450.*/
89 GX_DISPLAY   *display;
90 GX_BRUSH     *brush;
91 GX_RECTANGLE *clip;
92 GX_RECTANGLE  arc_clip[4];
93 GX_POINT      point;
94 GX_POINT      inner_start;
95 GX_POINT      inner_end;
96 GX_POINT      outer_start;
97 GX_POINT      outer_end;
98 INT           sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
99 INT          *pLineEnds;
100 INT           ymin;
101 INT           ymax;
102 INT           xstart;
103 INT           xend;
104 INT           ystart;
105 INT           yend;
106 INT           curx;
107 INT           cury;
108 INT           nextx;
109 INT           nexty;
110 INT           dx;
111 INT           dy;
112 INT           Index;
113 INT           Index1;
114 INT           loop;
115 INT           height;
116 INT           xsign;
117 INT           ysign;
118 INT           error;
119 INT           decision;
120 INT           brush_width;
121 GX_UBYTE      alpha1;
122 GX_UBYTE      alpha2;
123 VOID          (*blend_func)(GX_DRAW_CONTEXT *, INT, INT, GX_COLOR, GX_UBYTE);
124 GX_BOOL       right = GX_TRUE;
125 INT           test;
126 INT           cur_shift;
127 INT           next_shift;
128 
129     if ((start_angle >= 90) &&
130         (start_angle <= 270) &&
131         (end_angle <= 270))
132     {
133         right = GX_FALSE;
134     }
135 
136     display = context -> gx_draw_context_display;
137     brush = &context -> gx_draw_context_brush;
138     brush_width = brush -> gx_brush_width;
139     blend_func = display -> gx_display_driver_pixel_blend;
140 
141     if (blend_func == GX_NULL)
142     {
143         return;
144     }
145 
146     clip = context -> gx_draw_context_clip;
147     pLineEnds = _gx_system_scratchpad;
148 
149     if (r <= (UINT)((brush_width - 1) >> 1))
150     {
151         return;
152     }
153 
154     /* Calculate the ridius of the inner circle.  */
155     r = (UINT)(r - (UINT)((brush_width - 1) >> 1));
156 
157     /* Get end points. */
158     _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &inner_start);
159     _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &inner_end);
160     _gx_utility_circle_point_get(xcenter, ycenter, (UINT)(r + (UINT)brush_width - 1), start_angle, &outer_start);
161     _gx_utility_circle_point_get(xcenter, ycenter, (UINT)(r + (UINT)brush_width - 1), end_angle, &outer_end);
162 
163     ymin = ycenter - (INT)r - brush_width + 1;
164     ymax = ycenter + (INT)r + brush_width - 1;
165 
166     if (((start_angle < 90) && (end_angle < 90)) ||
167         ((start_angle > 90) && (end_angle < 450)))
168     {
169         if (outer_start.gx_point_y < outer_end.gx_point_y)
170         {
171             ymin = outer_start.gx_point_y;
172         }
173         else
174         {
175             ymin = outer_end.gx_point_y;
176         }
177 
178         if (inner_start.gx_point_y < ymin)
179         {
180             ymin = inner_start.gx_point_y;
181         }
182 
183         if (inner_end.gx_point_y < ymin)
184         {
185             ymin = inner_end.gx_point_y;
186         }
187     }
188 
189     if (clip -> gx_rectangle_top > ymin)
190     {
191         ymin = clip -> gx_rectangle_top;
192     }
193 
194     /* Calculate maximum y line. */
195     if (((start_angle < 270) && (end_angle < 270)) || (start_angle > 270))
196     {
197         if (outer_start.gx_point_y > outer_end.gx_point_y)
198         {
199             ymax = outer_start.gx_point_y;
200         }
201         else
202         {
203             ymax = outer_end.gx_point_y;
204         }
205 
206         if (inner_start.gx_point_y > ymax)
207         {
208             ymax = inner_start.gx_point_y;
209         }
210 
211         if (inner_end.gx_point_y > ymax)
212         {
213             ymax = inner_end.gx_point_y;
214         }
215     }
216 
217     if (clip -> gx_rectangle_bottom < ymax)
218     {
219         ymax = clip -> gx_rectangle_bottom;
220     }
221 
222     height = ymax - ymin + 1;
223 
224     /* default the point array to being off the screen on both sides: */
225 
226     for (loop = 0; loop < height * 2; loop += 2)
227     {
228         pLineEnds[loop] = 2000;
229         pLineEnds[loop + 1] = 0;
230     }
231 
232     /* Get point array of inner arc and outer arc. */
233     for (Index1 = 0; Index1 < 2; Index1++)
234     {
235         if (Index1 == 1)
236         {
237             r += (UINT)(brush_width - 1);
238         }
239 
240         _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle,
241                                             &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
242 
243         curx = 0;
244         cury = (INT)r;
245         error = 0;
246 
247         while (curx < cury)
248         {
249             alpha1 = (GX_UBYTE)(255 - error);
250             alpha2 = (GX_UBYTE)error;
251 
252             for (loop = 0; loop < 4; loop++)
253             {
254                 point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
255                 point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
256 
257                 if ((_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
258                      _gx_utility_rectangle_point_detect(&arc_clip[1], point)) &&
259                     _gx_utility_rectangle_point_detect(clip, point))
260                 {
261                     /* Draw point(curx, cury).  */
262                     blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
263                 }
264 
265                 point.gx_point_y = (GX_VALUE)((cury - 1) * sign[loop][1] + ycenter);
266 
267                 if ((_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
268                      _gx_utility_rectangle_point_detect(&arc_clip[1], point)) &&
269                     _gx_utility_rectangle_point_detect(clip, point))
270                 {
271                     blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, (GX_UBYTE)alpha2);
272                 }
273 
274                 point.gx_point_x = (GX_VALUE)(cury * sign[loop][0] + xcenter);
275                 point.gx_point_y = (GX_VALUE)(curx * sign[loop][1] + ycenter);
276 
277                 if ((_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
278                      _gx_utility_rectangle_point_detect(&arc_clip[1], point)) &&
279                     _gx_utility_rectangle_point_detect(clip, point))
280                 {
281                     /* Draw point(cury, curx).  */
282                     blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color,  alpha1);
283                 }
284 
285                 if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
286                 {
287                     if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
288                         _gx_utility_rectangle_point_detect(&arc_clip[1], point))
289                     {
290                         Index = (point.gx_point_y - ymin) << 1;
291 
292                         if (right)
293                         {
294                             if (Index1 == 0)
295                             {
296                                 pLineEnds[Index] = cury * sign[loop][0] + xcenter;
297                             }
298                             else
299                             {
300                                 pLineEnds[Index + 1] = (cury - 1) * sign[loop][0] + xcenter;
301                             }
302                         }
303                         else
304                         {
305                             if (Index1 == 0)
306                             {
307                                 pLineEnds[Index + 1] = cury * sign[loop][0] + xcenter;
308                             }
309                             else
310                             {
311                                 pLineEnds[Index] = (cury - 1) * sign[loop][0] + xcenter;
312                             }
313                         }
314                     }
315                 }
316 
317                 point.gx_point_x = (GX_VALUE)((cury - 1) * sign[loop][0] + xcenter);
318 
319                 if ((_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
320                      _gx_utility_rectangle_point_detect(&arc_clip[1], point)) &&
321                     _gx_utility_rectangle_point_detect(clip, point))
322                 {
323                     /* Draw point(cury - 1, curx).  */
324                     blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, (GX_UBYTE)alpha2);
325                 }
326 
327                 if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
328                 {
329                     if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
330                         _gx_utility_rectangle_point_detect(&arc_clip[1], point))
331                     {
332                         Index = (point.gx_point_y - ymin) << 1;
333 
334                         if (right)
335                         {
336                             if (Index1 == 0)
337                             {
338                                 pLineEnds[Index] = cury * sign[loop][0] + xcenter;
339                             }
340                             else
341                             {
342                                 pLineEnds[Index + 1] = (cury - 1) * sign[loop][0] + xcenter;
343                             }
344                         }
345                         else
346                         {
347                             if (Index1 == 0)
348                             {
349                                 pLineEnds[Index + 1] = cury * sign[loop][0] + xcenter;
350                             }
351                             else
352                             {
353                                 pLineEnds[Index] = (cury - 1) * sign[loop][0] + xcenter;
354                             }
355                         }
356                     }
357                 }
358             }
359 
360             /* Calculate the distance between mathmatical point to drawing poing,
361                which is used to blending pixel.  */
362             curx++;
363             nexty = (INT)(r * r) - curx * curx;
364             error = (cury << 8) - (INT)(_gx_utility_math_sqrt((UINT)(nexty << 10)) << 3);
365 
366             while (error >= 255)
367             {
368                 error -= 255;
369                 cury--;
370 
371                 for (loop = 0; loop < 4; loop++)
372                 {
373                     point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
374                     point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
375 
376                     if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
377                     {
378                         if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
379                             _gx_utility_rectangle_point_detect(&arc_clip[1], point))
380                         {
381                             Index = (point.gx_point_y - ymin) << 1;
382 
383                             if (right)
384                             {
385                                 if (Index1 == 0)
386                                 {
387                                     pLineEnds[Index] = curx * sign[loop][0] + xcenter;
388                                 }
389                                 else
390                                 {
391                                     pLineEnds[Index + 1] = (curx - 1) * sign[loop][0] + xcenter;
392                                 }
393                             }
394                             else
395                             {
396                                 if (Index1 == 0)
397                                 {
398                                     pLineEnds[Index + 1] = curx * sign[loop][0] + xcenter;
399                                 }
400                                 else
401                                 {
402                                     pLineEnds[Index] = (curx - 1) * sign[loop][0] + xcenter;
403                                 }
404                             }
405                         }
406                     }
407                 }
408             }
409         }
410 
411         alpha1 = (GX_UBYTE)(255 - error);
412 
413         for (loop = 0; loop < 4; loop++)
414         {
415 
416             point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
417             point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
418 
419             if ((_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
420                  _gx_utility_rectangle_point_detect(&arc_clip[1], point)) &&
421                 _gx_utility_rectangle_point_detect(clip, point))
422             {
423                 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color,  alpha1);
424             }
425         }
426     }
427 
428     /* Fill in the point array by using Breshenhams line for
429        2 lines of the arc end.
430      */
431 
432     for (loop = 0; loop < 2; loop++)
433     {
434         if (loop == 0)
435         {
436             xstart = inner_start.gx_point_x;
437             ystart = inner_start.gx_point_y;
438             xend = outer_start.gx_point_x;
439             yend = outer_start.gx_point_y;
440         }
441         else
442         {
443             xstart = inner_end.gx_point_x;
444             ystart = inner_end.gx_point_y;
445             xend = outer_end.gx_point_x;
446             yend = outer_end.gx_point_y;
447         }
448 
449         dx = GX_ABS(xend - xstart);
450         dy = GX_ABS(yend - ystart);
451 
452         /* Horizontal Line. */
453         if (ystart == yend)
454         {
455             continue;
456         }
457 
458         /* Vertical Line. */
459         if (xstart == xend)
460         {
461             if (ystart > yend)
462             {
463                 GX_SWAP_VALS(xstart, xend);
464                 GX_SWAP_VALS(ystart, yend);
465             }
466 
467             for (cury = ystart; cury <= yend; cury++)
468             {
469                 if ((cury >= ymin) && (cury <= ymax))
470                 {
471                     Index = (cury - ymin) << 1;
472                     if (xstart <= pLineEnds[Index])
473                     {
474                         pLineEnds[Index] = xstart;
475                     }
476 
477                     if (xstart > pLineEnds[Index + 1])
478                     {
479                         pLineEnds[Index + 1] = xstart;
480                     }
481                 }
482             }
483             continue;
484         }
485 
486         /* Simple Line. */
487         if (((dx >= dy && (xstart > xend)) ||
488              ((dy > dx) && ystart > yend)))
489         {
490             GX_SWAP_VALS(xend, xstart);
491             GX_SWAP_VALS(yend, ystart);
492         }
493 
494         xsign = (xend - xstart) / dx;
495         ysign = (yend - ystart) / dy;
496 
497         cur_shift = 0;
498         next_shift = 0;
499 
500         if (dx >= dy)
501         {
502             if ((right && loop == 1) ||
503                 (!right && loop == 0))
504             {
505                 if (ysign > 0)
506                 {
507                     cur_shift = 1;
508                 }
509                 else
510                 {
511                     next_shift = 1;
512                 }
513             }
514             else
515             {
516                 if (ysign > 0)
517                 {
518                     next_shift = -1;
519                 }
520                 else
521                 {
522                     cur_shift = -1;
523                 }
524             }
525 
526             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
527                  decision = 0; curx <= nextx; curx++, nextx--,
528                  decision += dy)
529             {
530                 if (decision >= dx)
531                 {
532                     decision -= dx;
533                     cury += ysign;
534                     nexty -= ysign;
535                 }
536 
537                 test = cury + cur_shift;
538 
539                 if ((test >= ymin) && (test <= ymax))
540                 {
541                     Index = (test - ymin) << 1;
542 
543                     if (curx < pLineEnds[Index])
544                     {
545                         pLineEnds[Index] = curx;
546                     }
547 
548                     if (curx > pLineEnds[Index + 1])
549                     {
550                         pLineEnds[Index + 1] = curx;
551                     }
552                 }
553 
554                 test = nexty + next_shift;
555 
556                 if ((test >= ymin) && (test <= ymax))
557                 {
558                     Index1 = (test - ymin) << 1;
559 
560                     if (nextx < pLineEnds[Index1])
561                     {
562                         pLineEnds[Index1] = nextx;
563                     }
564 
565                     if (nextx > pLineEnds[Index1 + 1])
566                     {
567                         pLineEnds[Index1 + 1] = nextx;
568                     }
569                 }
570             }
571         }
572         else
573         {
574             if ((right && loop == 1) ||
575                 (!right && loop == 0))
576             {
577                 next_shift = -xsign;
578             }
579             else
580             {
581                 cur_shift = xsign;
582             }
583 
584             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
585                  decision = 0; cury <= nexty; cury++, nexty--,
586                  decision += dx)
587             {
588                 if (decision >= dy)
589                 {
590                     decision -= dy;
591                     curx += xsign;
592                     nextx -= xsign;
593                 }
594 
595                 if ((cury >= ymin) && (cury <= ymax))
596                 {
597 
598                     Index = (cury - ymin) << 1;
599                     test = curx + cur_shift;
600 
601                     if (test < pLineEnds[Index])
602                     {
603                         pLineEnds[Index] = test;
604                     }
605 
606                     if (test > pLineEnds[Index + 1])
607                     {
608                         pLineEnds[Index + 1] = test;
609                     }
610                 }
611 
612                 if ((nexty >= ymin) && (nexty <= ymax))
613                 {
614                     Index1 = (nexty - ymin) << 1;
615                     test = nextx + next_shift;
616 
617                     if (test < pLineEnds[Index1])
618                     {
619                         pLineEnds[Index1] = test;
620                     }
621 
622                     if (test > pLineEnds[Index1 + 1])
623                     {
624                         pLineEnds[Index1 + 1] = test;
625                     }
626                 }
627             }
628         }
629     }
630 
631     /* Filling the outline area with horizontal line. */
632 
633     Index = 0;
634     for (cury = ymin; cury <= ymax; cury++)
635     {
636         if (pLineEnds[Index] <= pLineEnds[Index + 1])
637         {
638             if (pLineEnds[Index] < clip -> gx_rectangle_left)
639             {
640                 pLineEnds[Index] = clip -> gx_rectangle_left;
641             }
642 
643             if (pLineEnds[Index + 1] > clip -> gx_rectangle_right)
644             {
645                 pLineEnds[Index + 1] = clip -> gx_rectangle_right;
646             }
647 
648             display -> gx_display_driver_horizontal_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], cury, 1,
649                                                               brush -> gx_brush_line_color);
650         }
651         Index += 2;
652     }
653 }
654 
655 /**************************************************************************/
656 /*                                                                        */
657 /*  FUNCTION                                               RELEASE        */
658 /*                                                                        */
659 /*    _gx_display_driver_generic_aliased_wide_arc_draw    PORTABLE C      */
660 /*                                                           6.1          */
661 /*  AUTHOR                                                                */
662 /*                                                                        */
663 /*    Kenneth Maxwell, Microsoft Corporation                              */
664 /*                                                                        */
665 /*  DESCRIPTION                                                           */
666 /*                                                                        */
667 /*    Display driver function to draw wide anti-aliased circular arc.     */
668 /*                                                                        */
669 /*  INPUT                                                                 */
670 /*                                                                        */
671 /*    context                             Drawing context                 */
672 /*    xcenter                             curx-coord of center of circle  */
673 /*    ycenter                             cury-coord of center of circle  */
674 /*    r                                   Radius of circle                */
675 /*                                                                        */
676 /*  OUTPUT                                                                */
677 /*                                                                        */
678 /*    None                                                                */
679 /*                                                                        */
680 /*  CALLS                                                                 */
681 /*                                                                        */
682 /*    [gx_display_driver_generic_simple_wide_arc_draw]                    */
683 /*                                          Real display driver wide arc  */
684 /*                                            draw function               */
685 /*    _gx_utility_circle_point_get          Get point coord on a circle   */
686 /*    _gx_canvas_circle_draw                Draw circle into a canvas     */
687 /*    [gx_display_driver_anti_aliased_line_draw]                          */
688 /*                                          Basic driver-level aliased    */
689 /*                                            line draw function          */
690 /*                                                                        */
691 /*  CALLED BY                                                             */
692 /*                                                                        */
693 /*    GUIX Internal Code                                                  */
694 /*                                                                        */
695 /*  RELEASE HISTORY                                                       */
696 /*                                                                        */
697 /*    DATE              NAME                      DESCRIPTION             */
698 /*                                                                        */
699 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
700 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
701 /*                                            resulting in version 6.1    */
702 /*                                                                        */
703 /**************************************************************************/
_gx_display_driver_generic_aliased_wide_arc_draw(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle)704 VOID _gx_display_driver_generic_aliased_wide_arc_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
705 {
706 GX_BRUSH   *brush;
707 INT         brush_width;
708 GX_POINT    startp;
709 GX_POINT    endp;
710 GX_DISPLAY *display;
711 GX_COLOR    old_fill;
712 UINT        old_style;
713 
714 #if defined(GX_BRUSH_ALPHA_SUPPORT)
715 GX_UBYTE old_alpha;
716 
717     old_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
718     context -> gx_draw_context_brush.gx_brush_alpha = GX_ALPHA_VALUE_OPAQUE;
719 #endif
720 
721     brush = &context -> gx_draw_context_brush;
722     brush_width = brush -> gx_brush_width;
723     display = context -> gx_draw_context_display;
724 
725     if (start_angle < 90)
726     {
727         if (end_angle <= 90)
728         {
729             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, end_angle);
730         }
731         else if (end_angle <= 270)
732         {
733             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 90);
734             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 90, end_angle);
735         }
736         else
737         {
738             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 90);
739             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 90, 270);
740             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 270, end_angle);
741         }
742     }
743     else if (start_angle < 270)
744     {
745         if (end_angle <= 270)
746         {
747             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, end_angle);
748         }
749         else if (end_angle <= 450)
750         {
751             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 270);
752             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 270, end_angle);
753         }
754         else
755         {
756             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 270);
757             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 270, 450);
758             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 90, end_angle - 360);
759         }
760     }
761     else
762     {
763         if (end_angle <= 450)
764         {
765             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, end_angle);
766         }
767         else if (end_angle <= 630)
768         {
769             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 450);
770             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 90, end_angle - 360);
771         }
772         else
773         {
774             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 450);
775             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 90, 270);
776             _gx_display_driver_generic_simple_aliased_wide_arc_draw(context, xcenter, ycenter, r, 270, end_angle - 360);
777         }
778     }
779 
780     old_fill = brush -> gx_brush_fill_color;
781     old_style = brush -> gx_brush_style;
782 
783     brush -> gx_brush_width = 1;
784     brush -> gx_brush_fill_color = brush -> gx_brush_line_color;
785     brush -> gx_brush_style |= GX_BRUSH_SOLID_FILL;
786 
787     r = (UINT)(r - (UINT)((brush_width - 1) >> 1));
788     _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &startp);
789     _gx_utility_circle_point_get(xcenter, ycenter, r + (UINT)brush_width - 1, start_angle, &endp);
790 
791     if (brush -> gx_brush_style & GX_BRUSH_ROUND)
792     {
793         brush -> gx_brush_style &= (ULONG)(~GX_BRUSH_PIXELMAP_FILL);
794 
795         _gx_display_driver_generic_aliased_filled_circle_draw(context,
796                                                               GX_FIXED_VAL_MAKE(startp.gx_point_x + endp.gx_point_x) >> 1,
797                                                               GX_FIXED_VAL_MAKE(startp.gx_point_y + endp.gx_point_y) >> 1,
798                                                               GX_FIXED_VAL_MAKE(brush_width) >> 1);
799     }
800     else
801     {
802         display -> gx_display_driver_anti_aliased_line_draw(context,
803                                                             startp.gx_point_x,
804                                                             startp.gx_point_y,
805                                                             endp.gx_point_x,
806                                                             endp.gx_point_y);
807     }
808 
809     _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &startp);
810     _gx_utility_circle_point_get(xcenter, ycenter, r + (UINT)brush_width - 1, end_angle, &endp);
811 
812     if (brush -> gx_brush_style & GX_BRUSH_ROUND)
813     {
814         brush -> gx_brush_style &= (ULONG)(~GX_BRUSH_PIXELMAP_FILL);
815 
816         _gx_display_driver_generic_aliased_filled_circle_draw(context,
817                                                               GX_FIXED_VAL_MAKE(startp.gx_point_x + endp.gx_point_x) >> 1,
818                                                               GX_FIXED_VAL_MAKE(startp.gx_point_y + endp.gx_point_y) >> 1,
819                                                               GX_FIXED_VAL_MAKE(brush_width) >> 1);
820     }
821     else
822     {
823         display -> gx_display_driver_anti_aliased_line_draw(context,
824                                                             startp.gx_point_x,
825                                                             startp.gx_point_y,
826                                                             endp.gx_point_x,
827                                                             endp.gx_point_y);
828     }
829 
830     brush -> gx_brush_width = (GX_VALUE)brush_width;
831     brush -> gx_brush_fill_color = old_fill;
832     brush -> gx_brush_style = old_style;
833 
834 #if defined(GX_BRUSH_ALPHA_SUPPORT)
835     context -> gx_draw_context_brush.gx_brush_alpha = old_alpha;
836 #endif
837 }
838 #endif
839 
840