GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_simple_line_alpha_draw.c Lines: 158 158 100.0 %
Date: 2026-03-06 19:21:09 Branches: 120 120 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
23
#define PIXEL_WRITE(loc, val) (*(loc) = ((USHORT)val))
24
25
#define GX_SOURCE_CODE
26
27
/* Include necessary system files.  */
28
29
#include "gx_api.h"
30
#include "gx_utility.h"
31
#include "gx_display.h"
32
33
#if defined (GX_BRUSH_ALPHA_SUPPORT)
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _gx_display_driver_simple_line_alpha_draw           PORTABLE C      */
39
/*                                                           6.1          */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Kenneth Maxwell, Microsoft Corporation                              */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    Generic driver function that handles drawing lines with brush       */
47
/*    alpha.                                                              */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    context                               Drawing context               */
52
/*    xstart                                x-coord of endpoint           */
53
/*    ystart                                y-coord of endpoint           */
54
/*    xend                                  x-coord of endpoint           */
55
/*    yend                                  y-coord of endpoint           */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    None                                                                */
60
/*                                                                        */
61
/*  CALLS                                                                 */
62
/*                                                                        */
63
/*    GX_ABS                                Compute the absolute value    */
64
/*    GX_SWAP_VALUE                         Swap two values               */
65
/*    [PIXEL_WRITE]                         Driver level pixel write      */
66
/*                                            routine                     */
67
/*    [gx_display_driver_pixel_blend]       Basic display driver pixel    */
68
/*                                            blend function              */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    GUIX Internal Code                                                  */
73
/*                                                                        */
74
/**************************************************************************/
75
493
VOID _gx_display_driver_simple_line_alpha_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend, GX_UBYTE alpha)
76
{
77
INT           curx;
78
INT           cury;
79
INT           x_sign;
80
INT           y_sign;
81
INT           decision;
82
INT           nextx;
83
INT           nexty;
84
GX_POINT      end_point;
85
GX_POINT      mid_point;
86
GX_RECTANGLE  half_rectangle;
87
GX_RECTANGLE  half_over;
88
INT           sign;
89
INT           steps;
90
493
GX_BOOL       clipped = GX_TRUE;
91
493
INT           dx = GX_ABS(xend - xstart);
92
493
INT           dy = GX_ABS(yend - ystart);
93
94
493
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
95
493
GX_COLOR      linecolor = context -> gx_draw_context_brush.gx_brush_line_color;
96
VOID        (*blend_func)(GX_DRAW_CONTEXT *context, INT x, INT y, GX_COLOR fcolor, GX_UBYTE alpha);
97
98
493
    blend_func = context -> gx_draw_context_display -> gx_display_driver_pixel_blend;
99
100
493
    if (blend_func == GX_NULL)
101
    {
102
25
        return;
103
    }
104
105


468
    if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
106
    {
107
206
        GX_SWAP_VALS(xend, xstart);
108
206
        GX_SWAP_VALS(yend, ystart);
109
    }
110
468
    x_sign = (xend - xstart) / dx;
111
468
    y_sign = (yend - ystart) / dy;
112
113
468
    end_point.gx_point_x = (GX_VALUE)xstart;
114
468
    end_point.gx_point_y = (GX_VALUE)ystart;
115
116
468
    if (_gx_utility_rectangle_point_detect(clip, end_point))
117
    {
118
276
        end_point.gx_point_x = (GX_VALUE)xend;
119
276
        end_point.gx_point_y = (GX_VALUE)yend;
120
121
276
        if (_gx_utility_rectangle_point_detect(clip, end_point))
122
        {
123
87
            clipped = GX_FALSE;
124
        }
125
    }
126
127
468
    if (clipped)
128
    {
129
        /* here if we must do clipping in the inner loop, because one
130
        or both of the end points are outside clipping rectangle */
131
132
        /* Calculate the middle point of the line.  */
133
381
        mid_point.gx_point_x = (GX_VALUE)((xend + xstart) >> 1);
134
381
        mid_point.gx_point_y = (GX_VALUE)((yend + ystart) >> 1);
135
136
        /* Judge the clip in which side.  */
137
381
        if (_gx_utility_rectangle_point_detect(clip, mid_point))
138
        {
139
140
            /* the clip in two sides.  */
141
217
            if (dx >= dy)
142
            {
143
                /* walk out the clipping point.  */
144
3099
                for (curx = xstart, cury = ystart, decision = (dx >> 1); curx < mid_point.gx_point_x;
145
2971
                    curx++, decision += dy)
146
                {
147
3096
                    if (decision >= dx)
148
                    {
149
1825
                        decision -= dx;
150
1825
                        cury += y_sign;
151
                    }
152
153
3096
                    if (curx >= clip -> gx_rectangle_left &&
154
1777
                        cury >= clip -> gx_rectangle_top &&
155
1478
                        cury <= clip -> gx_rectangle_bottom)
156
                    {
157
125
                        break;
158
                    }
159
                }
160
8864
                for (; curx <= mid_point.gx_point_x;
161
8736
                    curx++, decision += dy)
162
                {
163
8736
                    if (decision >= dx)
164
                    {
165
4802
                        decision -= dx;
166
4802
                        cury += y_sign;
167
                    }
168
169
8736
                    blend_func(context, curx, cury, linecolor, alpha);
170
                }
171
6716
                for (nextx = xend, nexty = yend, decision = (dx >> 1); nextx > mid_point.gx_point_x;
172
6588
                    nextx--, decision += dy)
173
                {
174
6713
                    if (decision >= dx)
175
                    {
176
3339
                        decision -= dx;
177
3339
                        nexty -= y_sign;
178
                    }
179
6713
                    if (nextx <= clip -> gx_rectangle_right &&
180
1016
                        nexty >= clip -> gx_rectangle_top &&
181
891
                        nexty <= clip -> gx_rectangle_bottom)
182
                    {
183
125
                        break;
184
                    }
185
                }
186
187
5142
                for (; nextx > mid_point.gx_point_x;
188
5014
                    nextx--, decision += dy)
189
                {
190
5014
                    if (decision >= dx)
191
                    {
192
3204
                        decision -= dx;
193
3204
                        nexty -= y_sign;
194
                    }
195
5014
                    blend_func(context, nextx, nexty, linecolor, alpha);
196
                }
197
            }
198
            else
199
            {
200
4484
                for (nextx = xend, nexty = yend, decision = (dy >> 1); nexty > mid_point.gx_point_y;
201
4395
                    nexty--, decision += dx)
202
                {
203
4481
                    if (decision >= dy)
204
                    {
205
2301
                        decision -= dy;
206
2301
                        nextx -= x_sign;
207
                    }
208
4481
                    if (nextx >= clip -> gx_rectangle_left &&
209
4252
                        nextx <= clip -> gx_rectangle_right &&
210
1674
                        nexty <= clip -> gx_rectangle_bottom)
211
                    {
212
86
                        break;
213
                    }
214
                }
215
216
2689
                for (; nexty > mid_point.gx_point_y;
217
2600
                    nexty--, decision += dx)
218
                {
219
2600
                    if (decision >= dy)
220
                    {
221
1261
                        decision -= dy;
222
1261
                        nextx -= x_sign;
223
                    }
224
2600
                    blend_func(context, nextx, nexty, linecolor, alpha);
225
                }
226
227
                /* walk out the clipping point.  */
228
2748
                for (curx = xstart, cury = ystart, decision = (dy >> 1); cury < mid_point.gx_point_y;
229
2659
                    cury++, decision += dx)
230
                {
231
2745
                    if (decision >= dy)
232
                    {
233
1461
                        decision -= dy;
234
1461
                        curx += x_sign;
235
                    }
236
237
2745
                    if (curx >= clip -> gx_rectangle_left &&
238
2601
                        curx <= clip -> gx_rectangle_right &&
239
297
                        cury >= clip -> gx_rectangle_top)
240
                    {
241
86
                        break;
242
                    }
243
                }
244
4502
                for (; cury <= mid_point.gx_point_y;
245
4413
                    cury++, decision += dx)
246
                {
247
4413
                    if (decision >= dy)
248
                    {
249
2166
                        decision -= dy;
250
2166
                        curx += x_sign;
251
                    }
252
4413
                    blend_func(context, curx, cury, linecolor, alpha);
253
                }
254
            }
255
        }
256
        else
257
        {
258
            /* The clip stay at one side.  */
259
164
            if (dx >= dy)
260
            {
261
82
                half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
262
82
                half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
263
82
                if (y_sign == 1)
264
                {
265
40
                    half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
266
40
                    half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
267
                }
268
                else
269
                {
270
42
                    half_rectangle.gx_rectangle_top = mid_point.gx_point_y;
271
42
                    half_rectangle.gx_rectangle_bottom = (GX_VALUE)ystart;
272
                }
273
274
82
                if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
275
                {
276
62
                    curx = xstart;
277
62
                    cury = ystart;
278
62
                    steps = mid_point.gx_point_x - curx + 1;
279
62
                    sign = 1;
280
                }
281
                else
282
                {
283
20
                    curx = xend;
284
20
                    cury = yend;
285
20
                    steps = xend - mid_point.gx_point_x;
286
20
                    sign = -1;
287
20
                    y_sign = 0 - y_sign;
288
                }
289
8877
                for (decision = (dx >> 1); steps > 0; curx += sign, decision += dy, steps--)
290
                {
291
8795
                    if (decision >= dx)
292
                    {
293
4182
                        decision -= dx;
294
4182
                        cury += y_sign;
295
                    }
296
297
8795
                    if (curx >= clip -> gx_rectangle_left &&
298
8748
                        curx <= clip -> gx_rectangle_right &&
299
5894
                        cury >= clip -> gx_rectangle_top &&
300
5766
                        cury <= clip -> gx_rectangle_bottom)
301
                    {
302
5613
                        blend_func(context, curx, cury, linecolor, alpha);
303
                    }
304
                }
305
            }
306
            else
307
            {
308
82
                half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
309
82
                half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
310
82
                if (x_sign == 1)
311
                {
312
42
                    half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
313
42
                    half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
314
                }
315
                else
316
                {
317
40
                    half_rectangle.gx_rectangle_right = (GX_VALUE)xstart;
318
40
                    half_rectangle.gx_rectangle_left = mid_point.gx_point_x;
319
                }
320
321
82
                if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
322
                {
323
42
                    curx = xstart;
324
42
                    cury = ystart;
325
42
                    steps = mid_point.gx_point_y - cury + 1;
326
42
                    sign = 1;
327
                }
328
                else
329
                {
330
40
                    curx = xend;
331
40
                    cury = yend;
332
40
                    steps = yend - mid_point.gx_point_y;
333
40
                    sign = -1;
334
40
                    x_sign = 0 - x_sign;
335
                }
336
337
7702
                for (decision = (dy >> 1); steps > 0; cury += sign, decision += dx, steps--)
338
                {
339
7620
                    if (decision >= dy)
340
                    {
341
4010
                        decision -= dy;
342
4010
                        curx += x_sign;
343
                    }
344
7620
                    if (curx >= clip -> gx_rectangle_left &&
345
7599
                        curx <= clip -> gx_rectangle_right &&
346
5332
                        cury >= clip -> gx_rectangle_top &&
347
5263
                        cury <= clip -> gx_rectangle_bottom)
348
                    {
349
3982
                        blend_func(context, curx, cury, linecolor, alpha);
350
                    }
351
                }
352
            }
353
        }
354
    }
355
    else
356
    {
357
        /* here if both line ends lie within clipping rectangle, we can
358
        run a faster inner loop */
359
87
        if (dx >= dy)
360
        {
361
46
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
362
4051
                decision = (dx >> 1); curx <= nextx; curx++, nextx--,
363
4005
                decision += dy)
364
            {
365
366
4005
                if (decision >= dx)
367
                {
368
2196
                    decision -= dx;
369
2196
                    cury += y_sign;
370
2196
                    nexty -= y_sign;
371
372
                }
373
4005
                blend_func(context, curx, cury, linecolor, alpha);
374
4005
                blend_func(context, nextx, nexty, linecolor, alpha);
375
            }
376
        }
377
        else
378
        {
379
380
41
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
381
3697
                decision = (dy >> 1); cury <= nexty; cury++, nexty--,
382
3656
                decision += dx)
383
            {
384
3656
                if (decision >= dy)
385
                {
386
1822
                    decision -= dy;
387
1822
                    curx += x_sign;
388
1822
                    nextx -= x_sign;
389
                }
390
3656
                blend_func(context, curx, cury, linecolor, alpha);
391
3656
                blend_func(context, nextx, nexty, linecolor, alpha);
392
            }
393
        }
394
    }
395
}
396
397
#endif /* GX_BRUSH_ALPHA_SUPPORT */