GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_aliased_line_draw.c Lines: 152 152 100.0 %
Date: 2024-12-05 08:52:37 Branches: 124 124 100.0 %

Line Branch Exec Source
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_display.h"
28
#include "gx_utility.h"
29
30
31
/**************************************************************************/
32
/*                                                                        */
33
/*  FUNCTION                                               RELEASE        */
34
/*                                                                        */
35
/*    _gx_display_driver_generic_aliased_line_draw        PORTABLE C      */
36
/*                                                           6.1          */
37
/*  AUTHOR                                                                */
38
/*                                                                        */
39
/*    Kenneth Maxwell, Microsoft Corporation                              */
40
/*                                                                        */
41
/*  DESCRIPTION                                                           */
42
/*                                                                        */
43
/*    General anti-aliasing line drawing function.                        */
44
/*                                                                        */
45
/*  INPUT                                                                 */
46
/*                                                                        */
47
/*    context                               Drawing context               */
48
/*    xstart                                x-coord of endpoint           */
49
/*    ystart                                y-coord of endpoint           */
50
/*    xend                                  x-coord of endpoint           */
51
/*    yend                                  y-coord of endpoint           */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    None                                                                */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    [gx_display_driver_pixel_blend]       Display driver blend function */
60
/*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
61
/*                                            inside rectangle            */
62
/*    GX_SWAP_VALS                          Swap two values               */
63
/*    [gx_display_driver_simple_line_draw]  Basic display driver simple   */
64
/*                                            line draw function          */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    GUIX Internal Code                                                  */
69
/*                                                                        */
70
/*  RELEASE HISTORY                                                       */
71
/*                                                                        */
72
/*    DATE              NAME                      DESCRIPTION             */
73
/*                                                                        */
74
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
75
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
76
/*                                            resulting in version 6.1    */
77
/*                                                                        */
78
/**************************************************************************/
79
2446
VOID _gx_display_driver_generic_aliased_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
80
{
81
2446
GX_BRUSH     *brush = &context -> gx_draw_context_brush;
82
2446
GX_COLOR      line_color = brush -> gx_brush_line_color;
83
2446
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
84
85
VOID          (*blend_func)(GX_DRAW_CONTEXT *context,
86
                            INT x, INT y, GX_COLOR color, GX_UBYTE alpha);
87
88
2446
INT      dx = GX_ABS(xend - xstart);
89
2446
INT      dy = GX_ABS(yend - ystart);
90
GX_POINT point;
91
GX_POINT point2;
92
INT      curx;
93
INT      cury;
94
INT      decision;
95
INT      nextx;
96
INT      nexty;
97
INT      back_alpha;
98
INT      fore_alpha;
99
INT      x_sign;
100
INT      y_sign;
101
GX_UBYTE alpha;
102
103
#if defined(GX_BRUSH_ALPHA_SUPPORT)
104
GX_UBYTE brush_alpha;
105
106
2446
    brush_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
107
108
2446
    if (brush_alpha == 0)
109
    {
110
        /* Nothing to draw here. */
111
227
        return;
112
    }
113
#endif
114
115

2403
    if (!dx || !dy)
116
    {
117
143
        return;
118
    }
119
120
2260
    if (!(context -> gx_draw_context_display -> gx_display_driver_pixel_blend))
121
    {
122
1
        context -> gx_draw_context_display -> gx_display_driver_simple_line_draw(context, xstart, ystart, xend, yend);
123
1
        return;
124
    }
125
2259
    blend_func = context -> gx_draw_context_display -> gx_display_driver_pixel_blend;
126
127
    /* special case of 1x1 pixel line:*/
128
129

2259
    if (dx == 1 && dy == 1)
130
    {
131
40
        point.gx_point_x = (GX_VALUE)xstart;
132
40
        point.gx_point_y = (GX_VALUE)ystart;
133
134
40
        if (_gx_utility_rectangle_point_detect(clip, point))
135
        {
136
39
            alpha = 0xc0;
137
#if defined(GX_BRUSH_ALPHA_SUPPORT)
138
39
            alpha = (GX_UBYTE)(brush_alpha * alpha / 255);
139
#endif
140
39
            blend_func(context, xstart, ystart, line_color, alpha);
141
        }
142
40
        point.gx_point_x = (GX_VALUE)xend;
143
40
        point.gx_point_y = (GX_VALUE)yend;
144
145
40
        if (_gx_utility_rectangle_point_detect(clip, point))
146
        {
147
39
            alpha = 0x40;
148
#if defined(GX_BRUSH_ALPHA_SUPPORT)
149
39
            alpha = (GX_UBYTE)(brush_alpha * alpha / 255);
150
#endif
151
39
            blend_func(context, xend, yend, line_color, alpha);
152
        }
153
40
        point.gx_point_x = (GX_VALUE)xstart;
154
40
        point.gx_point_y = (GX_VALUE)yend;
155
156
40
        if (_gx_utility_rectangle_point_detect(clip, point))
157
        {
158
39
            alpha = 0x40;
159
#if defined(GX_BRUSH_ALPHA_SUPPORT)
160
39
            alpha = (GX_UBYTE)(brush_alpha * alpha / 255);
161
#endif
162
39
            blend_func(context, xstart, yend, line_color, alpha);
163
        }
164
40
        point.gx_point_x = (GX_VALUE)xend;
165
40
        point.gx_point_y = (GX_VALUE)ystart;
166
167
40
        if (_gx_utility_rectangle_point_detect(clip, point))
168
        {
169
39
            alpha = 0xc0;
170
#if defined(GX_BRUSH_ALPHA_SUPPORT)
171
39
            alpha = (GX_UBYTE)(brush_alpha * alpha / 255);
172
#endif
173
39
            blend_func(context, xend, ystart, line_color, alpha);
174
        }
175
40
        return;
176
    }
177
178


2219
    if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
179
    {
180
852
        GX_SWAP_VALS(xend, xstart);
181
852
        GX_SWAP_VALS(yend, ystart);
182
    }
183
184
2219
    x_sign = ((INT)xend - (INT)xstart) / dx;
185
2219
    y_sign = ((INT)yend - (INT)ystart) / dy;
186
187
2219
    point.gx_point_x = (GX_VALUE)xstart;
188
2219
    point.gx_point_y = (GX_VALUE)ystart;
189
2219
    point2.gx_point_x = (GX_VALUE)xend;
190
2219
    point2.gx_point_y = (GX_VALUE)yend;
191
192

4299
    if (_gx_utility_rectangle_point_detect(clip, point) &&
193
2080
        _gx_utility_rectangle_point_detect(clip, point2))
194
    {
195
        /* both endpoints are inside clip rectangle. We don't need to clip
196
           inside the inner loop */
197
198
1954
        if (dx >= dy)
199
        {
200
            /* draw anti-aliased line along x axis, no clipping */
201
1220
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
202
14421
                 decision = 0; curx <= nextx; curx++, nextx--,
203
13201
                 decision += dy)
204
            {
205
13201
                if (decision >= dx)
206
                {
207
6118
                    decision -= dx;
208
6118
                    cury += y_sign;
209
6118
                    nexty -= y_sign;
210
                }
211
212
13201
                back_alpha = ((decision << 8) / dx);
213
13201
                fore_alpha = 255 - back_alpha;
214
215
#if defined(GX_BRUSH_ALPHA_SUPPORT)
216
13201
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
217
13201
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
218
#endif
219
13201
                blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
220
13201
                blend_func(context, curx, cury + y_sign, line_color, (GX_UBYTE)back_alpha);
221
13201
                if (curx != nextx)
222
                {
223
12402
                    blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha);
224
12402
                    blend_func(context, nextx, nexty - y_sign, line_color, (GX_UBYTE)back_alpha);
225
                }
226
            }
227
        }
228
        else
229
        {
230
            /* draw anti-aliased line along y axis, no clipping */
231
734
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
232
12725
                 decision = 0; cury <= nexty; cury++, nexty--,
233
11991
                 decision += dx)
234
            {
235
11991
                if (decision >= dy)
236
                {
237
4036
                    decision -= dy;
238
4036
                    curx += x_sign;
239
4036
                    nextx -= x_sign;
240
                }
241
242
11991
                back_alpha = ((decision << 8) / dy);
243
11991
                fore_alpha = 255 - back_alpha;
244
245
#if defined(GX_BRUSH_ALPHA_SUPPORT)
246
11991
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
247
11991
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
248
#endif
249
11991
                blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
250
11991
                blend_func(context, curx + x_sign, cury, line_color,  (GX_UBYTE)back_alpha);
251
11991
                if (cury != nexty)
252
                {
253
11552
                    blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha);
254
11552
                    blend_func(context, nextx - x_sign, nexty, line_color,  (GX_UBYTE)back_alpha);
255
                }
256
            }
257
        }
258
    }
259
    else
260
    {
261
262
265
        if (dx >= dy)
263
        {
264
            /* draw anti-aliased line along x axis, clipping in the inner loop */
265
141
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
266
11400
                 decision = 0; curx <= nextx; curx++, nextx--,
267
11259
                 decision += dy)
268
            {
269
11259
                if (decision >= dx)
270
                {
271
6514
                    decision -= dx;
272
6514
                    cury += y_sign;
273
6514
                    nexty -= y_sign;
274
                }
275
276
11259
                back_alpha = ((decision << 8) / dx);
277
11259
                fore_alpha = 255 - back_alpha;
278
279
#if defined(GX_BRUSH_ALPHA_SUPPORT)
280
11259
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
281
11259
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
282
#endif
283
11259
                if (curx >= clip -> gx_rectangle_left &&
284
6096
                    curx <= clip -> gx_rectangle_right &&
285
5243
                    cury >= clip -> gx_rectangle_top &&
286
5104
                    cury <= clip -> gx_rectangle_bottom)
287
                {
288
4991
                    blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
289
                }
290
11259
                if (curx >= clip -> gx_rectangle_left &&
291
6096
                    curx <= clip -> gx_rectangle_right &&
292
5243
                    (cury + y_sign) >= clip -> gx_rectangle_top &&
293
5111
                    (cury + y_sign) <= clip -> gx_rectangle_bottom)
294
                {
295
4993
                    blend_func(context, curx, cury + y_sign, line_color, (GX_UBYTE)back_alpha);
296
                }
297
11259
                if (curx == nextx)
298
                {
299
108
                    continue;
300
                }
301
11151
                if (nextx >= clip -> gx_rectangle_left &&
302
10945
                    nextx <= clip -> gx_rectangle_right &&
303
5767
                    nexty >= clip -> gx_rectangle_top &&
304
5653
                    nexty <= clip -> gx_rectangle_bottom)
305
                {
306
5544
                    blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha);
307
                }
308
11151
                if (nextx >= clip -> gx_rectangle_left &&
309
10945
                    nextx <= clip -> gx_rectangle_right &&
310
5767
                    (nexty - y_sign) >= clip -> gx_rectangle_top &&
311
5654
                    (nexty - y_sign) <= clip -> gx_rectangle_bottom)
312
                {
313
5540
                    blend_func(context, nextx, nexty - y_sign, line_color, (GX_UBYTE)back_alpha);
314
                }
315
            }
316
        }
317
        else
318
        {
319
            /* draw anti-aliased line along y axis, clipping in the inner loop */
320
124
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
321
10903
                 decision = 0; cury <= nexty; cury++, nexty--,
322
10779
                 decision += dx)
323
            {
324
10779
                if (decision >= dy)
325
                {
326
6278
                    decision -= dy;
327
6278
                    curx += x_sign;
328
6278
                    nextx -= x_sign;
329
                }
330
331
10779
                back_alpha = ((decision << 8) / dy);
332
10779
                fore_alpha = 255 - back_alpha;
333
334
#if defined(GX_BRUSH_ALPHA_SUPPORT)
335
10779
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
336
10779
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
337
#endif
338
10779
                if (curx >= clip -> gx_rectangle_left &&
339
8643
                    curx <= clip -> gx_rectangle_right &&
340
7926
                    cury >= clip -> gx_rectangle_top &&
341
7340
                    cury <= clip -> gx_rectangle_bottom)
342
                {
343
6600
                    blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
344
                }
345
346
10779
                if ((curx + x_sign) >= clip -> gx_rectangle_left &&
347
8695
                    (curx + x_sign) <= clip -> gx_rectangle_right &&
348
7966
                    cury >= clip -> gx_rectangle_top &&
349
7374
                    cury <= clip -> gx_rectangle_bottom)
350
                {
351
6639
                    blend_func(context, curx + x_sign, cury, line_color, (GX_UBYTE)back_alpha);
352
                }
353
354
10779
                if (cury == nexty)
355
                {
356
110
                    continue;
357
                }
358
10669
                if (nextx >= clip -> gx_rectangle_left &&
359
9958
                    nextx <= clip -> gx_rectangle_right &&
360
6989
                    nexty >= clip -> gx_rectangle_top &&
361
6426
                    nexty <= clip -> gx_rectangle_bottom)
362
                {
363
3882
                    blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha);
364
                }
365
10669
                if ((nextx - x_sign) >= clip -> gx_rectangle_left &&
366
9958
                    (nextx - x_sign) <= clip -> gx_rectangle_right &&
367
7424
                    nexty >= clip -> gx_rectangle_top &&
368
6863
                    nexty <= clip -> gx_rectangle_bottom)
369
                {
370
4319
                    blend_func(context, nextx - x_sign, nexty, line_color, (GX_UBYTE)back_alpha);
371
                }
372
            }
373
        }
374
    }
375
}
376