GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_wide_arc_draw.c Lines: 214 214 100.0 %
Date: 2026-03-06 19:21:09 Branches: 166 166 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** GUIX Component                                                        */
17
/**                                                                       */
18
/**   Display Management (Display)                                        */
19
/**                                                                       */
20
/**************************************************************************/
21
22
#define GX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "gx_api.h"
28
#include "gx_system.h"
29
#include "gx_utility.h"
30
#include "gx_display.h"
31
#include "gx_canvas.h"
32
33
#if defined(GX_ARC_DRAWING_SUPPORT)
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _gx_display_driver_generic_simple_wide_arc_draw     PORTABLE C      */
39
/*                                                           6.1          */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Kenneth Maxwell, Microsoft Corporation                              */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    Innner help function that draw a wide arc between [90, 180] or      */
47
/*    [270, 540].                                                         */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    context                               Drawing context               */
52
/*    xcenter                               x-coord of center of circle   */
53
/*    ycenter                               y-coord of center of circle   */
54
/*    r                                     Radius of circle              */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    None                                                                */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _gx_display_driver_arc_clipping_get   Get an arc clipping.          */
63
/*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
64
/*                                            inside rectangle            */
65
/*    [gx_display_driver_line_draw]         The generic display driver    */
66
/*                                            line drawing routine        */
67
/*    _gx_utility_circle_point_get          Get point coord on a circle   */
68
/*                                                                        */
69
/*  CALLED BY                                                             */
70
/*                                                                        */
71
/*    _gx_display_driver_generic_wide_arc_draw                            */
72
/*                                                                        */
73
/**************************************************************************/
74
2656
static VOID _gx_display_driver_generic_simple_wide_arc_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
75
{
76
/* The function draw a wide arc between 90 and 270 or beween 270 and 450.*/
77
GX_DISPLAY   *display;
78
GX_BRUSH     *brush;
79
GX_RECTANGLE *clip;
80
GX_RECTANGLE  arc_clip[4];
81
GX_POINT      point;
82
GX_POINT      inner_start;
83
GX_POINT      inner_end;
84
GX_POINT      outer_start;
85
GX_POINT      outer_end;
86
2656
INT           sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
87
INT          *pLineEnds;
88
INT           ymin;
89
INT           ymax;
90
INT           xstart;
91
INT           xend;
92
INT           ystart;
93
INT           yend;
94
INT           curx;
95
INT           cury;
96
INT           nextx;
97
INT           nexty;
98
INT           dx;
99
INT           dy;
100
INT           Index;
101
INT           Index1;
102
INT           loop;
103
INT           height;
104
INT           xsign;
105
INT           ysign;
106
INT           decision;
107
INT           brush_width;
108
VOID          (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
109
110
111
2656
    display = context -> gx_draw_context_display;
112
2656
    brush = &context -> gx_draw_context_brush;
113
2656
    brush_width = brush -> gx_brush_width;
114
2656
    line_draw = display -> gx_display_driver_horizontal_line_draw;
115
116
2656
    if (r <= (UINT)((brush_width - 1) >> 1))
117
    {
118
546
        return;
119
    }
120
121
2110
    clip = context -> gx_draw_context_clip;
122
2110
    pLineEnds = _gx_system_scratchpad;
123
124
2110
    ymin = ycenter - (INT)r - (brush_width >> 1);
125
2110
    ymax = ycenter + (INT)r + (brush_width >> 1);
126
127
    /* Get end points. */
128
2110
    _gx_utility_circle_point_get(xcenter, ycenter, r - (UINT)((brush_width - 1) >> 1), start_angle, &inner_start);
129
2110
    _gx_utility_circle_point_get(xcenter, ycenter, r - (UINT)((brush_width - 1) >> 1), end_angle, &inner_end);
130
2110
    _gx_utility_circle_point_get(xcenter, ycenter, r + (UINT)(brush_width >> 1), start_angle, &outer_start);
131
2110
    _gx_utility_circle_point_get(xcenter, ycenter, r + (UINT)(brush_width >> 1), end_angle, &outer_end);
132
133

2110
    if (((start_angle < 90) && (end_angle < 90)) ||
134
1092
        ((start_angle > 90) && (end_angle < 450)))
135
    {
136
918
        if (outer_start.gx_point_y < outer_end.gx_point_y)
137
        {
138
283
            ymin = outer_start.gx_point_y;
139
        }
140
        else
141
        {
142
635
            ymin = outer_end.gx_point_y;
143
        }
144
145
918
        if (inner_start.gx_point_y < ymin)
146
        {
147
325
            ymin = inner_start.gx_point_y;
148
        }
149
150
918
        if (inner_end.gx_point_y < ymin)
151
        {
152
227
            ymin = inner_end.gx_point_y;
153
        }
154
    }
155
156
2110
    if (clip -> gx_rectangle_top > ymin)
157
    {
158
72
        ymin = clip -> gx_rectangle_top;
159
    }
160
161
    /* Calculate maximum y line. */
162

2110
    if (((start_angle < 270) && (end_angle < 270)) || (start_angle > 270))
163
    {
164
1277
        if (outer_start.gx_point_y > outer_end.gx_point_y)
165
        {
166
936
            ymax = outer_start.gx_point_y;
167
        }
168
        else
169
        {
170
341
            ymax = outer_end.gx_point_y;
171
        }
172
173
1277
        if (inner_start.gx_point_y > ymax)
174
        {
175
528
            ymax = inner_start.gx_point_y;
176
        }
177
178
1277
        if (inner_end.gx_point_y > ymax)
179
        {
180
107
            ymax = inner_end.gx_point_y;
181
        }
182
    }
183
184
2110
    if (clip -> gx_rectangle_bottom < ymax)
185
    {
186
141
        ymax = clip -> gx_rectangle_bottom;
187
    }
188
189
2110
    height = ymax - ymin + 1;
190
191
    /* default the point array to being off the screen on both sides: */
192
193
246375
    for (loop = 0; loop < height * 2; loop += 2)
194
    {
195
244265
        pLineEnds[loop] = 2000;
196
244265
        pLineEnds[loop + 1] = 0;
197
    }
198
199
2110
    r = (UINT)(r - (UINT)((brush_width - 1) >> 1));
200
201
    /* Get point array of inner arc and outer arc. */
202
6330
    for (Index1 = 0; Index1 < 2; Index1++)
203
    {
204
4220
        if (Index1 == 1)
205
        {
206
2110
            r += (UINT)(brush_width - 1);
207
        }
208
209
4220
        _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle,
210
                                            &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
211
212
4220
        curx = 0;
213
4220
        cury = (INT)r;
214
4220
        decision = 5 - (INT)(4 * r);
215
216
403432
        while (curx <= cury)
217
        {
218
1996060
            for (loop = 0; loop < 4; loop++)
219
            {
220
1596848
                point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
221
1596848
                point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
222
223

1596848
                if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
224
                {
225

1097094
                    if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
226
434294
                        _gx_utility_rectangle_point_detect(&arc_clip[1], point))
227
                    {
228
315756
                        Index = (point.gx_point_y - ymin) << 1;
229
315756
                        if (point.gx_point_x < pLineEnds[Index])
230
                        {
231
188485
                            pLineEnds[Index] = point.gx_point_x;
232
                        }
233
234
315756
                        if (point.gx_point_x > pLineEnds[Index + 1])
235
                        {
236
206488
                            pLineEnds[Index + 1] = point.gx_point_x;
237
                        }
238
                    }
239
                }
240
241
1596848
                point.gx_point_x = (GX_VALUE)(cury * sign[loop][0] + xcenter);
242
1596848
                point.gx_point_y = (GX_VALUE)(curx * sign[loop][1] + ycenter);
243
244

1596848
                if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
245
                {
246

1133181
                    if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
247
461901
                        _gx_utility_rectangle_point_detect(&arc_clip[1], point))
248
                    {
249
332384
                        Index = (point.gx_point_y - ymin) << 1;
250
332384
                        if (point.gx_point_x < pLineEnds[Index])
251
                        {
252
231464
                            pLineEnds[Index] = point.gx_point_x;
253
                        }
254
255
332384
                        if (point.gx_point_x > pLineEnds[Index + 1])
256
                        {
257
251383
                            pLineEnds[Index + 1] = point.gx_point_x;
258
                        }
259
                    }
260
                }
261
            }
262
263
399212
            if (decision < 0)
264
            {
265
231828
                decision += 8 * curx + 12;
266
            }
267
            else
268
            {
269
167384
                decision += 8 * (curx - cury) + 20;
270
167384
                cury--;
271
            }
272
399212
            curx++;
273
        }
274
    }
275
276
    /* Fill in the point array by using Breshenhams line for
277
       2 lines of the arc end.
278
     */
279
280
6330
    for (loop = 0; loop < 2; loop++)
281
    {
282
4220
        if (loop == 0)
283
        {
284
2110
            xstart = inner_start.gx_point_x;
285
2110
            ystart = inner_start.gx_point_y;
286
2110
            xend = outer_start.gx_point_x;
287
2110
            yend = outer_start.gx_point_y;
288
        }
289
        else
290
        {
291
2110
            xstart = inner_end.gx_point_x;
292
2110
            ystart = inner_end.gx_point_y;
293
2110
            xend = outer_end.gx_point_x;
294
2110
            yend = outer_end.gx_point_y;
295
        }
296
297
4220
        dx = GX_ABS(xend - xstart);
298
4220
        dy = GX_ABS(yend - ystart);
299
300
        /* Horizontal Line. */
301
4220
        if (ystart == yend)
302
        {
303
156
            continue;
304
        }
305
306
        /* Vertical Line. */
307
4064
        if (xstart == xend)
308
        {
309
2247
            if (ystart > yend)
310
            {
311
1245
                GX_SWAP_VALS(xstart, xend);
312
1245
                GX_SWAP_VALS(ystart, yend);
313
            }
314
315
23543
            for (cury = ystart; cury <= yend; cury++)
316
            {
317

21296
                if ((cury >= ymin) && (cury <= ymax))
318
                {
319
20760
                    Index = (cury - ymin) << 1;
320
20760
                    if (xstart <= pLineEnds[Index])
321
                    {
322
11493
                        pLineEnds[Index] = xstart;
323
                    }
324
325
20760
                    if (xstart > pLineEnds[Index + 1])
326
                    {
327
8419
                        pLineEnds[Index + 1] = xstart;
328
                    }
329
                }
330
            }
331
2247
            continue;
332
        }
333
334
        /* Simple Line. */
335
336

1817
        if (((dx >= dy && (xstart > xend)) ||
337
654
             ((dy > dx) && ystart > yend)))
338
        {
339
429
            GX_SWAP_VALS(xend, xstart);
340
429
            GX_SWAP_VALS(yend, ystart);
341
        }
342
343
1817
        xsign = (xend - xstart) / dx;
344
1817
        ysign = (yend - ystart) / dy;
345
346
1817
        if (dx >= dy)
347
        {
348
1163
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
349
7170
                 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
350
6007
                 decision += dy)
351
            {
352
6007
                if (decision >= dx)
353
                {
354
1699
                    decision -= dx;
355
1699
                    cury += ysign;
356
1699
                    nexty -= ysign;
357
                }
358
359

6007
                if ((cury >= ymin) && (cury <= ymax))
360
                {
361
5971
                    Index = (cury - ymin) << 1;
362
363
5971
                    if (curx < pLineEnds[Index])
364
                    {
365
1026
                        pLineEnds[Index] = curx;
366
                    }
367
368
5971
                    if (curx > pLineEnds[Index + 1])
369
                    {
370
2106
                        pLineEnds[Index + 1] = curx;
371
                    }
372
                }
373
374

6007
                if ((nexty >= ymin) && (nexty <= ymax))
375
                {
376
5971
                    Index = (nexty - ymin) << 1;
377
378
5971
                    if (nextx < pLineEnds[Index])
379
                    {
380
1620
                        pLineEnds[Index] = nextx;
381
                    }
382
383
5971
                    if (nextx > pLineEnds[Index + 1])
384
                    {
385
646
                        pLineEnds[Index + 1] = nextx;
386
                    }
387
                }
388
            }
389
        }
390
        else
391
        {
392
654
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
393
4519
                 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
394
3865
                 decision += dx)
395
            {
396
3865
                if (decision >= dy)
397
                {
398
1096
                    decision -= dy;
399
1096
                    curx += xsign;
400
1096
                    nextx -= xsign;
401
                }
402
403

3865
                if ((cury >= ymin) && (cury <= ymax))
404
                {
405
3844
                    Index = (cury - ymin) << 1;
406
3844
                    if (curx < pLineEnds[Index])
407
                    {
408
2001
                        pLineEnds[Index] = curx;
409
                    }
410
411
3844
                    if (curx > pLineEnds[Index + 1])
412
                    {
413
1529
                        pLineEnds[Index + 1] = curx;
414
                    }
415
                }
416
417
418

3865
                if ((nexty >= ymin) && (nexty <= ymax))
419
                {
420
3684
                    Index = (nexty - ymin) << 1;
421
422
3684
                    if (nextx < pLineEnds[Index])
423
                    {
424
1757
                        pLineEnds[Index] = nextx;
425
                    }
426
427
3684
                    if (nextx > pLineEnds[Index + 1])
428
                    {
429
1450
                        pLineEnds[Index + 1] = nextx;
430
                    }
431
                }
432
            }
433
        }
434
    }
435
436
    /* Filling the outline area with horizontal line. */
437
2110
    Index = 0;
438
246375
    for (cury = ymin; cury <= ymax; cury++)
439
    {
440
244265
        if (pLineEnds[Index] < pLineEnds[Index + 1])
441
        {
442
243637
            if (pLineEnds[Index] < clip -> gx_rectangle_left)
443
            {
444
13451
                pLineEnds[Index] = clip -> gx_rectangle_left;
445
            }
446
447
243637
            if (pLineEnds[Index + 1] > clip -> gx_rectangle_right)
448
            {
449
20981
                pLineEnds[Index + 1] = clip -> gx_rectangle_right;
450
            }
451
452
243637
            line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], cury, 1,
453
                      brush -> gx_brush_line_color);
454
        }
455
456
244265
        Index += 2;
457
    }
458
}
459
460
/**************************************************************************/
461
/*                                                                        */
462
/*  FUNCTION                                               RELEASE        */
463
/*                                                                        */
464
/*    _gx_display_driver_generic_wide_arc_draw            PORTABLE C      */
465
/*                                                           6.1          */
466
/*  AUTHOR                                                                */
467
/*                                                                        */
468
/*    Kenneth Maxwell, Microsoft Corporation                              */
469
/*                                                                        */
470
/*  DESCRIPTION                                                           */
471
/*                                                                        */
472
/*    Display driver function to draw simple circular arcle with wide     */
473
/*    outline.                                                            */
474
/*                                                                        */
475
/*  INPUT                                                                 */
476
/*                                                                        */
477
/*    context                               Drawing context               */
478
/*    xcenter                               x-coord of center of circle   */
479
/*    ycenter                               y-coord of center of circle   */
480
/*    r                                     Radius of circle              */
481
/*                                                                        */
482
/*  OUTPUT                                                                */
483
/*                                                                        */
484
/*    None                                                                */
485
/*                                                                        */
486
/*  CALLS                                                                 */
487
/*                                                                        */
488
/*    [_gx_display_driver_generic_simple_wide_arc_draw]                   */
489
/*                                          Real arc draw function        */
490
/*                                                                        */
491
/*  CALLED BY                                                             */
492
/*                                                                        */
493
/*    GUIX Internal Code                                                  */
494
/*                                                                        */
495
/**************************************************************************/
496
1612
VOID _gx_display_driver_generic_wide_arc_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
497
{
498
GX_BRUSH *brush;
499
INT       brush_width;
500
GX_POINT  startp;
501
GX_POINT  endp;
502
GX_COLOR  old_fill;
503
UINT      old_style;
504
505
#if defined(GX_BRUSH_ALPHA_SUPPORT)
506
GX_UBYTE old_alpha;
507
1612
    old_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
508
1612
    context -> gx_draw_context_brush.gx_brush_alpha = GX_ALPHA_VALUE_OPAQUE;
509
#endif
510
511
1612
    if (start_angle < 90)
512
    {
513
765
        if (end_angle <= 90)
514
        {
515
502
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, end_angle);
516
        }
517
263
        else if (end_angle <= 270)
518
        {
519
129
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 90);
520
129
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 90, end_angle);
521
        }
522
        else
523
        {
524
134
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 90);
525
134
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 90, 270);
526
134
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 270, end_angle);
527
        }
528
    }
529
847
    else if (start_angle < 270)
530
    {
531
291
        if (end_angle <= 270)
532
        {
533
75
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, end_angle);
534
        }
535
216
        else if (end_angle <= 450)
536
        {
537
92
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 270);
538
92
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 270, end_angle);
539
        }
540
        else
541
        {
542
124
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 270);
543
124
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 270, 450);
544
124
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 90, end_angle - 360);
545
        }
546
    }
547
    else
548
    {
549
556
        if (end_angle <= 450)
550
        {
551
376
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, end_angle);
552
        }
553
180
        else if (end_angle <= 630)
554
        {
555
53
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 450);
556
53
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 90, end_angle - 360);
557
        }
558
        else
559
        {
560
127
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, start_angle, 450);
561
127
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 90, 270);
562
127
            _gx_display_driver_generic_simple_wide_arc_draw(context, xcenter, ycenter, r, 270, end_angle - 360);
563
        }
564
    }
565
566
1612
    brush = &context -> gx_draw_context_brush;
567
1612
    brush_width = brush -> gx_brush_width;
568
1612
    old_fill = brush -> gx_brush_fill_color;
569
1612
    old_style = brush -> gx_brush_style;
570
571
1612
    brush -> gx_brush_width = 1;
572
1612
    brush -> gx_brush_fill_color = brush -> gx_brush_line_color;
573
1612
    brush -> gx_brush_style |= GX_BRUSH_SOLID_FILL;
574
575
1612
    r = (UINT)(r - (UINT)((brush_width - 1) >> 1));
576
1612
    _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &startp);
577
1612
    _gx_utility_circle_point_get(xcenter, ycenter, r + (UINT)(brush_width - 1), start_angle, &endp);
578
579
1612
    if (brush -> gx_brush_style & GX_BRUSH_ROUND)
580
    {
581
714
        brush -> gx_brush_style &= (ULONG)(~GX_BRUSH_PIXELMAP_FILL);
582
714
        _gx_display_driver_generic_filled_circle_draw(context,
583
714
                                                      GX_FIXED_VAL_MAKE(startp.gx_point_x + endp.gx_point_x) >> 1,
584
714
                                                      GX_FIXED_VAL_MAKE(startp.gx_point_y + endp.gx_point_y) >> 1,
585
714
                                                      GX_FIXED_VAL_MAKE(brush_width) >> 1);
586
    }
587
588
1612
    _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &startp);
589
1612
    _gx_utility_circle_point_get(xcenter, ycenter, r + (UINT)(brush_width - 1), end_angle, &endp);
590
591
1612
    if (brush -> gx_brush_style & GX_BRUSH_ROUND)
592
    {
593
714
        brush -> gx_brush_style &= (ULONG)(~GX_BRUSH_PIXELMAP_FILL);
594
714
        _gx_display_driver_generic_filled_circle_draw(context,
595
714
                                                      GX_FIXED_VAL_MAKE(startp.gx_point_x + endp.gx_point_x) >> 1,
596
714
                                                      GX_FIXED_VAL_MAKE(startp.gx_point_y + endp.gx_point_y) >> 1,
597
714
                                                      GX_FIXED_VAL_MAKE(brush_width) >> 1);
598
    }
599
600
1612
    brush -> gx_brush_width = (GX_VALUE)brush_width;
601
1612
    brush -> gx_brush_fill_color = old_fill;
602
1612
    brush -> gx_brush_style = old_style;
603
#if defined(GX_BRUSH_ALPHA_SUPPORT)
604
1612
    context -> gx_draw_context_brush.gx_brush_alpha = old_alpha;
605
#endif
606
1612
}
607
#endif
608