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


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