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 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _gx_display_driver_generic_rotated_simple_pie_fill  PORTABLE C      */
35 /*                                                           6.1.5        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Kenneth Maxwell, Microsoft Corporation                              */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    Display driver to fill a pie chart.                                 */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    context                               Drawing context               */
47 /*    xcenter                               x-coord of center of circle   */
48 /*    ycenter                               y-coord of center of circle   */
49 /*    r                                     Radius of circle              */
50 /*    start_angle                           Starting angle                */
51 /*    end_angle                             Ending angle                  */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _gx_display_driver_arc_clipping_get   Get an arc clipping.          */
60 /*    _gx_utility_rectangle_overlap_detect  Detects two rectangles being  */
61 /*                                            overlap                     */
62 /*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
63 /*                                            inside rectangle            */
64 /*    _gx_display_driver_circle_point_get   Get point coord on a circle   */
65 /*    [gx_display_driver_horizontal_pixelmap_line_draw]                   */
66 /*                                          Basic display driver          */
67 /*                                            horizontal pixelmap line    */
68 /*                                            draw function               */
69 /*    [gx_display_driver_horizontal_line_draw]                            */
70 /*                                          Basic display driver          */
71 /*                                            horizontal line draw routine*/
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    GUIX Internal Code                                                  */
76 /*                                                                        */
77 /*  RELEASE HISTORY                                                       */
78 /*                                                                        */
79 /*    DATE              NAME                      DESCRIPTION             */
80 /*                                                                        */
81 /*  12-31-2020     Kenneth Maxwell          Initial Version 6.1.3         */
82 /*  03-02-2021     Ting Zhu                 Modified comment(s),          */
83 /*                                            improved logic,             */
84 /*                                            resulting in version 6.1.5  */
85 /*                                                                        */
86 /**************************************************************************/
87 #if defined(GX_ARC_DRAWING_SUPPORT)
88 
_gx_display_driver_generic_rotated_simple_pie_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle,GX_BOOL skip_end)89 static VOID _gx_display_driver_generic_rotated_simple_pie_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter,
90                                                                UINT r, INT start_angle, INT end_angle, GX_BOOL skip_end)
91 {
92 /* The function will only fill a pie with both start angle and end angle are
93    between 0 and 180 or beween 180 and 360.*/
94 
95 GX_DISPLAY           *display;
96 GX_BRUSH             *brush;
97 GX_RECTANGLE         *clip;
98 GX_RECTANGLE          arc_clip[4];
99 GX_POINT              point;
100 GX_POINT              points[3];
101 INT                   sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
102 INT                  *pLineEnds;
103 GX_POINT             *pGet;
104 INT                   xmin;
105 INT                   xmax;
106 INT                   xstart;
107 INT                   xend;
108 INT                   ystart;
109 INT                   yend;
110 INT                   curx;
111 INT                   cury;
112 INT                   nextx;
113 INT                   nexty;
114 INT                   dx;
115 INT                   dy;
116 INT                   Index;
117 INT                   loop;
118 INT                   width;
119 INT                   xsign;
120 INT                   ysign;
121 INT                   decision;
122 int                   fillingwards;
123 VOID                  (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
124 INT                   xpos = 0;
125 GX_PIXELMAP          *pixelmap = GX_NULL;
126 INT                   skip_line;
127 GX_FILL_PIXELMAP_INFO info;
128 
129     display = context -> gx_draw_context_display;
130     brush = &context -> gx_draw_context_brush;
131     line_draw = display -> gx_display_driver_vertical_line_draw;
132 
133     if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
134     {
135         if (brush -> gx_brush_pixelmap == GX_NULL)
136         {
137             return;
138         }
139 
140         /* Pick up brush pixelmap. */
141         pixelmap = brush -> gx_brush_pixelmap;
142 
143         if (pixelmap -> gx_pixelmap_format != display -> gx_display_color_format)
144         {
145             /* Display driver only support its native format pixelmap.*/
146             /* Nothing should be drawn if pixelmap format isn't support. */
147             return;
148         }
149 
150         memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
151 
152         info.pixelmap = pixelmap;
153         info.current_pixel_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_data;
154         if (pixelmap -> gx_pixelmap_aux_data_size)
155         {
156             info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
157         }
158     }
159 
160     pGet = points;
161 
162     points[1].gx_point_x = (GX_VALUE)xcenter;
163     points[1].gx_point_y = (GX_VALUE)ycenter;
164 
165     _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &points[0]);
166     _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &points[2]);
167 
168     _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle,
169                                         &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
170 
171     /* Pie is in left side. */
172     xmin = points[0].gx_point_x;
173     xmax = points[2].gx_point_x;
174 
175     if (xmin > xmax)
176     {
177         GX_SWAP_VALS(xmin, xmax);
178     }
179 
180     if (xmax < xcenter)
181     {
182         xmax = xcenter;
183     }
184     else if (xmin > xcenter)
185     {
186         xmin = xcenter;
187     }
188 
189     clip = context -> gx_draw_context_clip;
190 
191     if (clip -> gx_rectangle_left > xmin)
192     {
193         xmin = clip -> gx_rectangle_left;
194     }
195 
196     if (clip -> gx_rectangle_right < xmax)
197     {
198         xmax = clip -> gx_rectangle_right;
199     }
200 
201     width = xmax - xmin + 1;
202 
203     pLineEnds = _gx_system_scratchpad;
204 
205     /* default the point array to being off the screen on both sides: */
206 
207     for (loop = 0; loop < width * 2; loop += 2)
208     {
209         pLineEnds[loop] = 2000;
210         pLineEnds[loop + 1] = 0;
211     }
212 
213     curx = 0;
214     cury = (INT)r;
215     decision = 5 - (INT)(4 * r);
216 
217     while (curx <= cury)
218     {
219         for (loop = 0; loop < 4; loop++)
220         {
221             point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
222             point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
223 
224             if ((point.gx_point_x >= xmin) && (point.gx_point_x <= xmax))
225             {
226                 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
227                     _gx_utility_rectangle_point_detect(&arc_clip[1], point))
228                 {
229                     Index = (point.gx_point_x - xmin) << 1;
230                     if (point.gx_point_y < pLineEnds[Index])
231                     {
232                         pLineEnds[Index] = point.gx_point_y;
233                     }
234 
235                     if (point.gx_point_y > pLineEnds[Index + 1])
236                     {
237                         pLineEnds[Index + 1] = point.gx_point_y;
238                     }
239                 }
240             }
241 
242             point.gx_point_x = (GX_VALUE)(cury * sign[loop][0] + xcenter);
243             point.gx_point_y = (GX_VALUE)(curx * sign[loop][1] + ycenter);
244 
245             if ((point.gx_point_x >= xmin) && (point.gx_point_x <= xmax))
246             {
247                 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
248                     _gx_utility_rectangle_point_detect(&arc_clip[1], point))
249                 {
250                     Index = (point.gx_point_x - xmin) << 1;
251                     if (point.gx_point_y < pLineEnds[Index])
252                     {
253                         pLineEnds[Index] = point.gx_point_y;
254                     }
255 
256                     if (point.gx_point_y > pLineEnds[Index + 1])
257                     {
258                         pLineEnds[Index + 1] = point.gx_point_y;
259                     }
260                 }
261             }
262         }
263 
264         if (decision < 0)
265         {
266             decision += 8 * curx + 12;
267         }
268         else
269         {
270             decision += 8 * (curx - cury) + 20;
271             cury--;
272         }
273         curx++;
274     }
275 
276     /* Fill in the point array by using Breshenhams line for
277        2 lines of circle sector
278      */
279 
280     for (loop = 0; loop < 2; loop++)
281     {
282         xstart = pGet -> gx_point_x;
283         ystart = pGet -> gx_point_y;
284         pGet++;
285         xend = pGet -> gx_point_x;
286         yend = pGet -> gx_point_y;
287         dx = GX_ABS(xend - xstart);
288         dy = GX_ABS(yend - ystart);
289 
290         /* Vertical Line. */
291         if (xstart == xend)
292         {
293             continue;
294         }
295 
296         /* Horizontal Line. */
297         if (ystart == yend)
298         {
299             if (xstart > xend)
300             {
301                 GX_SWAP_VALS(xstart, xend);
302                 GX_SWAP_VALS(ystart, yend);
303             }
304 
305             if (skip_end)
306             {
307                 ystart--;
308             }
309 
310             for (curx = xstart; curx <= xend; curx++)
311             {
312                 if ((curx >= xmin) && (curx <= xmax))
313                 {
314                     Index = (curx - xmin) << 1;
315                     if (ystart < pLineEnds[Index])
316                     {
317                         pLineEnds[Index] = ystart;
318                     }
319 
320                     if (ystart > pLineEnds[Index + 1])
321                     {
322                         pLineEnds[Index + 1] = ystart;
323                     }
324                 }
325             }
326             continue;
327         }
328 
329         /* Simple Line. */
330         if (((dx >= dy && (xstart > xend)) ||
331              ((dy > dx) && ystart > yend)))
332         {
333             GX_SWAP_VALS(xend, xstart);
334             GX_SWAP_VALS(yend, ystart);
335         }
336 
337         xsign = (xend - xstart) / dx;
338         ysign = (yend - ystart) / dy;
339 
340         if (dx >= dy)
341         {
342             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
343                  decision = (dx >> 1); curx <= nextx; curx++, nextx--,
344                  decision += dy)
345             {
346                 if (decision >= dx)
347                 {
348                     decision -= dx;
349                     cury += ysign;
350                     nexty -= ysign;
351                 }
352 
353                 if ((curx >= xmin) && (curx <= xmax))
354                 {
355                     Index = (curx - xmin) << 1;
356 
357                     if (cury < pLineEnds[Index])
358                     {
359                         pLineEnds[Index] = cury;
360                     }
361 
362                     if (cury - 1 > pLineEnds[Index + 1])
363                     {
364                         pLineEnds[Index + 1] = cury - 1;
365                     }
366                 }
367 
368                 if ((nextx >= xmin) && (nextx <= xmax))
369                 {
370                     Index = (nextx - xmin) << 1;
371 
372                     if (nexty < pLineEnds[Index])
373                     {
374                         pLineEnds[Index] = nexty;
375                     }
376 
377                     if (nexty - 1 > pLineEnds[Index + 1])
378                     {
379                         pLineEnds[Index + 1] = nexty - 1;
380                     }
381                 }
382             }
383         }
384         else
385         {
386             if (start_angle < 180)
387             {
388                 if (loop == 0)
389                 {
390                     fillingwards = 0;
391                 }
392                 else
393                 {
394                     fillingwards = 1;
395                 }
396             }
397             else
398             {
399                 if (loop == 0)
400                 {
401                     fillingwards = 1;
402                 }
403                 else
404                 {
405                     fillingwards = 0;
406                 }
407             }
408 
409             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
410                  decision = (dy >> 1); cury <= nexty; cury++, nexty--,
411                  decision += dx)
412             {
413                 if (decision >= dy)
414                 {
415                     decision -= dy;
416                     curx += xsign;
417                     nextx -= xsign;
418                 }
419 
420                 if ((curx - 1 + fillingwards >= xmin) && (curx - 1 + fillingwards <= xmax))
421                 {
422                     Index = (curx - 1 + fillingwards - xmin) << 1;
423 
424                     if (cury < pLineEnds[Index])
425                     {
426                         pLineEnds[Index] = cury;
427                     }
428 
429                     if (cury > pLineEnds[Index + 1])
430                     {
431                         pLineEnds[Index + 1] = cury;
432                     }
433                 }
434 
435                 if ((nextx - 1 + fillingwards >= xmin) && (nextx - 1 + fillingwards <= xmax))
436                 {
437                     Index = (nextx - 1 + fillingwards - xmin) << 1;
438 
439                     if (nexty < pLineEnds[Index])
440                     {
441                         pLineEnds[Index] = nexty;
442                     }
443 
444                     if (nexty > pLineEnds[Index + 1])
445                     {
446                         pLineEnds[Index + 1] = nexty;
447                     }
448                 }
449             }
450         }
451     }
452 
453     /* Filling circle sector with horizontal line. */
454     if (pixelmap)
455     {
456         if (context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_CW)
457         {
458             skip_line = (xmax - (xcenter - (INT)r) + 1) % pixelmap -> gx_pixelmap_width;
459 
460             /*Skip the un-draw line.*/
461             if (skip_line)
462             {
463                 skip_line = pixelmap -> gx_pixelmap_width - skip_line;
464             }
465 
466             Index = (width - 1) << 1;
467             xsign = -1;
468             xstart = xmax;
469         }
470         else
471         {
472             skip_line = (xmin - clip -> gx_rectangle_left);
473 
474             Index = 0;
475             xsign = 1;
476             xstart = xmin;
477         }
478 
479         /*Skip the un-draw line.*/
480         if (skip_line)
481         {
482             info.draw = GX_FALSE;
483             while (skip_line--)
484             {
485                 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, 0, &info);
486             }
487         }
488 
489         info.draw = GX_TRUE;
490         xpos = ycenter - (INT)r;
491 
492         for (curx = xmin; curx <= xmax; curx++)
493         {
494             if (pLineEnds[Index] < clip -> gx_rectangle_top)
495             {
496                 pLineEnds[Index] = clip -> gx_rectangle_top;
497             }
498 
499             if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
500             {
501                 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
502             }
503 
504             info.x_offset = pLineEnds[Index] - xpos;
505 
506             /* Filling pie area with pixelmap. */
507             display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], xstart, &info);
508 
509             xstart += xsign;
510             Index += xsign;
511             Index += xsign;
512         }
513     }
514     else
515     {
516         Index = 0;
517         for (curx = xmin; curx <= xmax; curx++)
518         {
519             if (pLineEnds[Index] < clip -> gx_rectangle_top)
520             {
521                 pLineEnds[Index] = clip -> gx_rectangle_top;
522             }
523 
524             if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
525             {
526                 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
527             }
528 
529             if (pLineEnds[Index] <= pLineEnds[Index + 1])
530             {
531                 line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], curx, 1,
532                           brush -> gx_brush_fill_color);
533             }
534 
535             Index += 2;
536         }
537     }
538 }
539 
540 /**************************************************************************/
541 /*                                                                        */
542 /*  FUNCTION                                               RELEASE        */
543 /*                                                                        */
544 /*    _gx_display_driver_generic_rotated_pie_fill         PORTABLE C      */
545 /*                                                           6.1.3        */
546 /*  AUTHOR                                                                */
547 /*                                                                        */
548 /*    Kenneth Maxwell, Microsoft Corporation                              */
549 /*                                                                        */
550 /*  DESCRIPTION                                                           */
551 /*                                                                        */
552 /*    Display driver to fill a pie.                                       */
553 /*                                                                        */
554 /*  INPUT                                                                 */
555 /*                                                                        */
556 /*    context                               Drawing context               */
557 /*    xcenter                               x-coord of center of circle   */
558 /*    ycenter                               y-coord of center of circle   */
559 /*    r                                     Radius of circle              */
560 /*    start_angle                           The start angle of circle arc */
561 /*    end_angle                             The end angle of circle arc   */
562 /*                                                                        */
563 /*  OUTPUT                                                                */
564 /*                                                                        */
565 /*    None                                                                */
566 /*                                                                        */
567 /*  CALLS                                                                 */
568 /*                                                                        */
569 /*    _gx_display_driver_generic_simple_pie_fill                          */
570 /*                                          Real display driver draw      */
571 /*                                            filled-pie function         */
572 /*                                                                        */
573 /*  CALLED BY                                                             */
574 /*                                                                        */
575 /*    _gx_canvas_pie_draw                                                 */
576 /*                                                                        */
577 /*  RELEASE HISTORY                                                       */
578 /*                                                                        */
579 /*    DATE              NAME                      DESCRIPTION             */
580 /*                                                                        */
581 /*  12-31-2020     Kenneth Maxwell          Initial Version 6.1.3         */
582 /*                                                                        */
583 /**************************************************************************/
_gx_display_driver_generic_rotated_pie_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle)584 VOID _gx_display_driver_generic_rotated_pie_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
585 {
586     /* The function fills a pie.*/
587 
588 
589     if (start_angle < 180)
590     {
591         if (end_angle < 180)
592         {
593             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, end_angle, GX_FALSE);
594         }
595         else if (end_angle < 360)
596         {
597             /* Skip-end parameter should only be set when drawing the above area.
598                It would be set to GX_TRUE to skip the bottom line to avoid case that this line will be drawn twice, which
599                is not correct, when brush alpha is set. */
600             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 180, GX_TRUE);
601             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 180, end_angle, GX_FALSE);
602         }
603         else
604         {
605             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 180, GX_TRUE);
606             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 180, 360, GX_FALSE);
607             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 0, end_angle - 360, GX_TRUE);
608         }
609     }
610     else
611     {
612         if (end_angle < 360)
613         {
614             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, end_angle, GX_FALSE);
615         }
616         else if (end_angle < 540)
617         {
618             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 360, GX_FALSE);
619             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 0, end_angle - 360, GX_TRUE);
620         }
621         else
622         {
623             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, start_angle, 360, GX_FALSE);
624             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 0, 180, GX_TRUE);
625             _gx_display_driver_generic_rotated_simple_pie_fill(context, xcenter, ycenter, r, 180, end_angle - 360, GX_FALSE);
626         }
627     }
628 }
629 
630 #endif
631 
632