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