GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_aliased_fixed_point_line_draw.c Lines: 128 128 100.0 %
Date: 2024-12-05 08:52:37 Branches: 110 110 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_fixed_point_line_draw            */
36
/*                                                        PORTABLE C      */
37
/*                                                           6.1.7        */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Kenneth Maxwell, Microsoft Corporation                              */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    General anti-aliasing line drawing function.                        */
45
/*                                                                        */
46
/*  INPUT                                                                 */
47
/*                                                                        */
48
/*    context                               Drawing context               */
49
/*    xstart                                x-coord of endpoint           */
50
/*    ystart                                y-coord of endpoint           */
51
/*    xend                                  x-coord of endpoint           */
52
/*    yend                                  y-coord of endpoint           */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    None                                                                */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    [gx_display_driver_pixel_blend]       Display driver blend function */
61
/*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
62
/*                                            inside rectangle            */
63
/*    GX_SWAP_VALS                          Swap two values               */
64
/*    [gx_display_driver_simple_line_draw]  Basic display driver simple   */
65
/*                                            line draw function          */
66
/*                                                                        */
67
/*  CALLED BY                                                             */
68
/*                                                                        */
69
/*    GUIX Internal Code                                                  */
70
/*                                                                        */
71
/*  RELEASE HISTORY                                                       */
72
/*                                                                        */
73
/*    DATE              NAME                      DESCRIPTION             */
74
/*                                                                        */
75
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
76
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
77
/*                                            resulting in version 6.1    */
78
/*  06-02-2021     Ting Zhu                 Modified comment(s),          */
79
/*                                            fixed compile warnings,     */
80
/*                                            resulting in version 6.1.7  */
81
/*                                                                        */
82
/**************************************************************************/
83
20839
VOID _gx_display_driver_generic_aliased_fixed_point_line_draw(GX_DRAW_CONTEXT *context,
84
                                                              GX_FIXED_VAL xstart, GX_FIXED_VAL ystart,
85
                                                              GX_FIXED_VAL xend, GX_FIXED_VAL yend)
86
{
87
20839
GX_BRUSH     *brush = &context -> gx_draw_context_brush;
88
20839
GX_COLOR      line_color = brush -> gx_brush_line_color;
89
20839
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
90
91
VOID          (*blend_func)(GX_DRAW_CONTEXT *context,
92
                            INT x, INT y, GX_COLOR color, GX_UBYTE alpha);
93
94
20839
GX_FIXED_VAL dx = GX_ABS(xend - xstart);
95
20839
GX_FIXED_VAL dy = GX_ABS(yend - ystart);
96
GX_FIXED_VAL x_fraction;
97
GX_FIXED_VAL y_fraction;
98
GX_POINT     point;
99
GX_POINT     point2;
100
20839
INT          curx = 0;
101
20839
INT          cury = 0;
102
INT          decision;
103
INT          back_alpha;
104
INT          fore_alpha;
105
INT          x_sign;
106
INT          y_sign;
107
108
#if defined(GX_BRUSH_ALPHA_SUPPORT)
109
GX_UBYTE brush_alpha;
110
111
20839
    brush_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
112
113
20839
    if (brush_alpha == 0)
114
    {
115
        /* Nothing to draw here. */
116
4
        return;
117
    }
118
#endif
119
120

20838
    if (!dx || !dy)
121
    {
122
2
        return;
123
    }
124
125
20836
    blend_func = context -> gx_draw_context_display -> gx_display_driver_pixel_blend;
126
127
20836
    if (blend_func == GX_NULL)
128
    {
129
1
        return;
130
    }
131
132


20835
    if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
133
    {
134
10418
        GX_SWAP_VALS(xend, xstart);
135
10418
        GX_SWAP_VALS(yend, ystart);
136
    }
137
138
20835
    x_sign = (xend - xstart) / dx;
139
20835
    y_sign = (yend - ystart) / dy;
140
141
20835
    x_fraction = (xstart & GX_FIXED_VAL_FRACTION_MASK);
142
20835
    y_fraction = (ystart & GX_FIXED_VAL_FRACTION_MASK);
143
144
20835
    if (dx >= dy)
145
    {
146
11022
        point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xstart);
147
11022
        point2.gx_point_x = (GX_VALUE)GX_FIXED_VAL_RND_UP(xend);
148
149
11022
        if (y_sign < 0)
150
        {
151
5774
            point.gx_point_y = (GX_VALUE)GX_FIXED_VAL_RND_UP(ystart);
152
5774
            point2.gx_point_y = (GX_VALUE)GX_FIXED_VAL_TO_INT(yend);
153
154
5774
            if (y_fraction)
155
            {
156
5708
                y_fraction = GX_FIXED_VAL_ONE - y_fraction;
157
            }
158
        }
159
        else
160
        {
161
5248
            point.gx_point_y = (GX_VALUE)GX_FIXED_VAL_TO_INT(ystart);
162
5248
            point2.gx_point_y = (GX_VALUE)GX_FIXED_VAL_RND_UP(yend);
163
        }
164
165
11022
        decision = (y_fraction * dx - x_fraction * dy) / GX_FIXED_VAL_ONE;
166
167
11022
        cury = point.gx_point_y;
168
169
11022
        if (decision < 0)
170
        {
171
2370
            decision += dx;
172
2370
            cury -= y_sign;
173
        }
174
    }
175
    else
176
    {
177
9813
        point.gx_point_y = (GX_VALUE)GX_FIXED_VAL_TO_INT(ystart);
178
9813
        point2.gx_point_y = (GX_VALUE)GX_FIXED_VAL_RND_UP(yend);
179
180
9813
        if (x_sign < 0)
181
        {
182
4643
            point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_RND_UP(xstart);
183
4643
            point2.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xend);
184
185
4643
            if (x_fraction)
186
            {
187
4642
                x_fraction = GX_FIXED_VAL_FRACTION_MASK - x_fraction;
188
            }
189
        }
190
        else
191
        {
192
5170
            point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xstart);
193
5170
            point2.gx_point_x = (GX_VALUE)GX_FIXED_VAL_RND_UP(xend);
194
        }
195
196
9813
        decision = (x_fraction * dy - y_fraction * dx) / GX_FIXED_VAL_ONE;
197
198
9813
        curx = point.gx_point_x;
199
200
9813
        if (decision < 0)
201
        {
202
1938
            decision += dy;
203
1938
            curx -= x_sign;
204
        }
205
    }
206
207

39746
    if (_gx_utility_rectangle_point_detect(clip, point) &&
208
18911
        _gx_utility_rectangle_point_detect(clip, point2))
209
    {
210
        /* both endpoints are inside clip rectangle. We don't need to clip
211
           inside the inner loop */
212
17603
        if (dx >= dy)
213
        {
214
            /* handle end points separately. */
215
216
            /* draw anti-aliased line along x axis, no clipping */
217
433161
            for (curx = point.gx_point_x; curx <= point2.gx_point_x; curx++, decision += dy)
218
            {
219
423769
                if (decision >= dx)
220
                {
221
219767
                    decision -= dx;
222
219767
                    cury += y_sign;
223
                }
224
225
423769
                back_alpha = ((decision << 8) / dx);
226
227
423769
                fore_alpha = 255 - back_alpha;
228
229

423769
                if ((curx == point.gx_point_x || curx == point2.gx_point_x) && x_fraction)
230
                {
231
18394
                    fore_alpha = fore_alpha * (GX_FIXED_VAL_ONE - x_fraction) / GX_FIXED_VAL_ONE;
232
18394
                    back_alpha = back_alpha * (GX_FIXED_VAL_ONE - x_fraction) / GX_FIXED_VAL_ONE;
233
18394
                    x_fraction = GX_FIXED_VAL_ONE - (xend & GX_FIXED_VAL_FRACTION_MASK);
234
                }
235
236
#if defined(GX_BRUSH_ALPHA_SUPPORT)
237
423769
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
238
423769
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
239
#endif
240
423769
                blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
241
423769
                blend_func(context, curx, cury + y_sign, line_color, (GX_UBYTE)back_alpha);
242
            }
243
        }
244
        else
245
        {
246
            /* draw anti-aliased line along y axis, no clipping */
247
416109
            for (cury = point.gx_point_y; cury <= point2.gx_point_y; cury++, decision += dx)
248
            {
249
407898
                if (decision >= dy)
250
                {
251
150775
                    decision -= dy;
252
150775
                    curx += x_sign;
253
                }
254
255
407898
                back_alpha = ((decision << 8) / dy);
256
407898
                fore_alpha = 255 - back_alpha;
257
258

407898
                if ((cury == point.gx_point_y || cury == point2.gx_point_y) && y_fraction)
259
                {
260
15940
                    fore_alpha = fore_alpha * (GX_FIXED_VAL_ONE - y_fraction) / GX_FIXED_VAL_ONE;
261
15940
                    back_alpha = back_alpha * (GX_FIXED_VAL_ONE - y_fraction) / GX_FIXED_VAL_ONE;
262
15940
                    y_fraction = GX_FIXED_VAL_ONE - (yend & GX_FIXED_VAL_FRACTION_MASK);
263
                }
264
265
#if defined(GX_BRUSH_ALPHA_SUPPORT)
266
407898
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
267
407898
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
268
#endif
269
407898
                blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
270
407898
                blend_func(context, curx + x_sign, cury, line_color, (GX_UBYTE)back_alpha);
271
            }
272
        }
273
    }
274
    else
275
    {
276
3232
        if (dx >= dy)
277
        {
278
            /* draw anti-aliased line along x axis, clipping in the inner loop */
279
106340
            for (curx = point.gx_point_x; curx <= point2.gx_point_x; curx++, decision += dy)
280
            {
281
104710
                if (decision >= dx)
282
                {
283
56522
                    decision -= dx;
284
56522
                    cury += y_sign;
285
                }
286
287
104710
                back_alpha = ((decision << 8) / dx);
288
104710
                fore_alpha = 255 - back_alpha;
289
290

104710
                if ((curx == point.gx_point_x || curx == point2.gx_point_x) && x_fraction)
291
                {
292
3236
                    fore_alpha = fore_alpha * (GX_FIXED_VAL_ONE - x_fraction) / GX_FIXED_VAL_ONE;
293
3236
                    back_alpha = back_alpha * (GX_FIXED_VAL_ONE - x_fraction) / GX_FIXED_VAL_ONE;
294
3236
                    x_fraction = GX_FIXED_VAL_ONE - (xend & GX_FIXED_VAL_FRACTION_MASK);
295
                }
296
297
#if defined(GX_BRUSH_ALPHA_SUPPORT)
298
104710
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
299
104710
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
300
#endif
301
104710
                if (curx >= clip -> gx_rectangle_left &&
302
78889
                    curx <= clip -> gx_rectangle_right &&
303
44753
                    cury >= clip -> gx_rectangle_top &&
304
44563
                    cury <= clip -> gx_rectangle_bottom)
305
                {
306
43247
                    blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
307
                }
308
309
104710
                if (curx >= clip -> gx_rectangle_left &&
310
78889
                    curx <= clip -> gx_rectangle_right &&
311
44753
                    (cury + y_sign) >= clip -> gx_rectangle_top &&
312
44563
                    (cury + y_sign) <= clip -> gx_rectangle_bottom)
313
                {
314
43232
                    blend_func(context, curx, cury + y_sign, line_color, (GX_UBYTE)back_alpha);
315
                }
316
            }
317
        }
318
        else
319
        {
320
137805
            for (cury = point.gx_point_y; cury <= point2.gx_point_y; cury++, decision += dx)
321
            {
322
136203
                if (decision >= dy)
323
                {
324
84923
                    decision -= dy;
325
84923
                    curx += x_sign;
326
                }
327
328
136203
                back_alpha = ((decision << 8) / dy);
329
136203
                fore_alpha = 255 - back_alpha;
330
331

136203
                if ((cury == point.gx_point_y || cury == point2.gx_point_y) && y_fraction)
332
                {
333
3108
                    fore_alpha = fore_alpha * (GX_FIXED_VAL_ONE - y_fraction) / GX_FIXED_VAL_ONE;
334
3108
                    back_alpha = back_alpha * (GX_FIXED_VAL_ONE - y_fraction) / GX_FIXED_VAL_ONE;
335
3108
                    y_fraction = GX_FIXED_VAL_ONE - (yend & GX_FIXED_VAL_FRACTION_MASK);
336
                }
337
338
#if defined(GX_BRUSH_ALPHA_SUPPORT)
339
136203
                fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255);
340
136203
                back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255);
341
#endif
342
136203
                if (curx >= clip -> gx_rectangle_left &&
343
125392
                    curx <= clip -> gx_rectangle_right &&
344
111794
                    cury >= clip -> gx_rectangle_top &&
345
110702
                    cury <= clip -> gx_rectangle_bottom)
346
                {
347
96218
                    blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha);
348
                }
349
350
136203
                if ((curx + x_sign) >= clip -> gx_rectangle_left &&
351
126040
                    (curx + x_sign) <= clip -> gx_rectangle_right &&
352
110934
                    cury >= clip -> gx_rectangle_top &&
353
109842
                    cury <= clip -> gx_rectangle_bottom)
354
                {
355
95358
                    blend_func(context, curx + x_sign, cury, line_color, (GX_UBYTE)back_alpha);
356
                }
357
            }
358
        }
359
    }
360
}
361