GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_canvas_line_draw.c Lines: 95 95 100.0 %
Date: 2026-03-06 19:21:09 Branches: 64 64 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
/**   Canvas Management (Canvas)                                          */
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_canvas.h"
31
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _gx_canvas_line_draw                                PORTABLE C      */
38
/*                                                           6.3.0        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Kenneth Maxwell, Microsoft Corporation                              */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This draws the specified line on the current context.               */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    x_start                            x-coord of endpoint1             */
50
/*    y_start                            y-coord of endpoint1             */
51
/*    x_end                              x-coord of endpoint2             */
52
/*    y_end                              y-coord of endpoint2             */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    status                             Completion status                */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    gx_utility_rectanlge_define        Define a rectangle               */
61
/*    gx_utility_rectangle_overlap_detect                                 */
62
/*                                       Detect rectangle overlap         */
63
/*    [gx_display_driver_line_draw]      The generic display driver line  */
64
/*                                         drawing routine                */
65
/*    [gx_display_driver_horizontal_line_draw]                            */
66
/*                                       The display driver horizontal    */
67
/*                                         line drawing function          */
68
/*    [gx_display_driver_vertical_line_draw]                              */
69
/*                                       The display driver vertical      */
70
/*                                         line drawing function          */
71
/*    [gx_display_driver_horizontal_pattern_line_draw]                    */
72
/*                                       The display driver horizontal    */
73
/*                                         pattern line drawing function  */
74
/*    [gx_display_driver_vertical_pattern_line_draw]                      */
75
/*                                       The display driver vertical      */
76
/*                                         pattern line drawing function  */
77
/*                                                                        */
78
/*  CALLED BY                                                             */
79
/*                                                                        */
80
/*    Application Code                                                    */
81
/*    GUIX Internal Code                                                  */
82
/*                                                                        */
83
/**************************************************************************/
84
6957407
UINT  _gx_canvas_line_draw(GX_VALUE x_start, GX_VALUE y_start, GX_VALUE x_end, GX_VALUE y_end)
85
{
86
GX_DRAW_CONTEXT *context;
87
GX_DISPLAY      *display;
88
GX_RECTANGLE     clip_rect;
89
GX_RECTANGLE     bound;
90
GX_VIEW         *view;
91
GX_BRUSH        *brush;
92
6957407
GX_BOOL          simple_line = GX_FALSE;
93
GX_VALUE         width;
94
GX_BOOL          anti_aliased;
95
GX_VALUE         brush_width;
96
97
    /* calculate rectangle that bounds the line. This bounding rectangle
98
       is later adjusted based on line width */
99
100
    /* are line coordinates left to right? */
101
102
6957407
    if (x_start <= x_end)
103
    {
104
        /* are line coordinates bottom to top? */
105
6948407
        if (y_start >= y_end)
106
        {
107
2993864
            _gx_utility_rectangle_define(&bound, x_start, y_end, x_end, y_start);
108
        }
109
        else
110
        {
111
            /* line is defined left to right, top to bottom */
112
3954543
            _gx_utility_rectangle_define(&bound, x_start, y_start, x_end, y_end);
113
        }
114
    }
115
    else
116
    {
117
9000
        if (y_start >= y_end)
118
        {
119
            /* line is defined right to left, bottom to top */
120
4667
            _gx_utility_rectangle_define(&bound, x_end, y_end, x_start, y_start);
121
        }
122
        else
123
        {
124
            /* line is defined right to left, top to bottom */
125
4333
            _gx_utility_rectangle_define(&bound, x_end, y_start, x_start, y_end);
126
        }
127
    }
128
129
    /* pick up the current drawing context */
130
6957407
    context = _gx_system_current_draw_context;
131
6957407
    brush = &context -> gx_draw_context_brush;
132
6957407
    brush_width = brush -> gx_brush_width;
133
134
6957407
    if (brush_width == 0)
135
    {
136
        /* Check brush width. Just return if width is 0. */
137
3837
        return(GX_SUCCESS);
138
    }
139
140
6953570
    if ((brush_width == 1) ||
141
173246
        ((brush -> gx_brush_style & GX_BRUSH_ROUND) == 0))
142
    {
143
        /* If we are drawing a horizontal or vertial line with
144
        square line ends, we can do a much simpler and faster
145
        line drawing function. Check for these special cases.
146
        */
147
148
        /* the brush 1 pixel wide or not round, check for horizontal or vertical */
149

6944737
        if ((y_start == y_end) || (x_start == x_end))
150
        {
151
            /* yes, simple line case */
152
6932831
            simple_line = GX_TRUE;
153
        }
154
    }
155
156
    /* pick up current display driver */
157
6953570
    display = context->gx_draw_context_display;
158
    /* Angled line using current context brush and canvas: */
159
6953570
    anti_aliased = GX_FALSE;
160
161
6953570
    if (brush -> gx_brush_style & GX_BRUSH_ALIAS)
162
    {
163
        /* The caller requested an anti-aliased line. Does the driver
164
        support it? */
165
33379
        if (brush_width == 1)
166
        {
167
24156
            if (display -> gx_display_driver_anti_aliased_line_draw)
168
            {
169
                /* Yes, the driver supports anti-aliased lines, so use them: */
170
23668
                anti_aliased = GX_TRUE;
171
            }
172
        }
173
        else
174
        {
175
9223
            if (display -> gx_display_driver_anti_aliased_wide_line_draw)
176
            {
177
                /* Yes, the driver supports anti-aliased lines, so use them: */
178
7272
                anti_aliased = GX_TRUE;
179
            }
180
        }
181
    }
182
183
    /* We need to expand the bounding rectangle to account for
184
       rounded ends and line width > 1
185
     */
186
6953570
    if (simple_line)
187
    {
188
6932831
        if(!brush -> gx_brush_line_pattern)
189
        {
190
6909684
            if (x_start == x_end)
191
            {
192
                /* vertical line centered around x coords */
193
3952706
                bound.gx_rectangle_left  = (GX_VALUE)(x_start - (brush_width / 2));
194
3952706
                bound.gx_rectangle_right = (GX_VALUE)(bound.gx_rectangle_left + brush_width - 1);
195
            }
196
            else
197
            {
198
                /* horizontal line centered around y coords */
199
2956978
                bound.gx_rectangle_top = (GX_VALUE)(y_start - (brush_width / 2));
200
2956978
                bound.gx_rectangle_bottom = (GX_VALUE)(bound.gx_rectangle_top + brush_width - 1);
201
            }
202
        }
203
    }
204
    else
205
    {
206
20739
        width = (GX_VALUE)((brush_width + 1) / 2);
207
208
20739
        if (anti_aliased)
209
        {
210
8507
            width = (GX_VALUE)(width + 1);
211
        }
212
213
        /* increase the bound by 1/2 the line width */
214
20739
        bound.gx_rectangle_top    = (GX_VALUE)(bound.gx_rectangle_top - width);
215
20739
        bound.gx_rectangle_left   = (GX_VALUE)(bound.gx_rectangle_left - width);
216
20739
        bound.gx_rectangle_right  = (GX_VALUE)(bound.gx_rectangle_right + width);
217
20739
        bound.gx_rectangle_bottom = (GX_VALUE)(bound.gx_rectangle_bottom + width);
218
    }
219
220
    /* clip the line bounding box to the dirty rectangle */
221
6953570
    if (!_gx_utility_rectangle_overlap_detect(&bound, &context -> gx_draw_context_dirty, &bound))
222
    {
223
        /* nothing to draw, return */
224
707607
        return GX_SUCCESS;
225
    }
226
227
    /* test to determine if the bounding rectangle overlaps the region we are allowed to draw
228
       into. For each view that overlaps the bounding rectangle, do some drawing.
229
     */
230
6245963
    view = context -> gx_draw_context_view_head;
231
232
12726918
    while (view)
233
    {
234
6480955
        if (!_gx_utility_rectangle_overlap_detect(&view -> gx_view_rectangle, &bound, &clip_rect))
235
        {
236
274076
            view = view -> gx_view_next;
237
274076
            continue;
238
        }
239
240
        /* we have a view into which we can draw the line, do it */
241
6206879
        context -> gx_draw_context_clip = &clip_rect;
242
243
6206879
        if (simple_line)
244
        {
245
6186863
            if (y_start == y_end)
246
            {
247
2652724
                if (brush -> gx_brush_line_pattern)
248
                {
249
11110
                    if (clip_rect.gx_rectangle_left > x_start)
250
                    {
251
11
                        width = (GX_VALUE)((clip_rect.gx_rectangle_left - x_start) & 0x1F);
252
11
                        context -> gx_draw_context_brush.gx_brush_pattern_mask >>= width;
253
                    }
254
255
                    /* Call display driver's simple horizontal pattern line drawing function.  */
256
11110
                    display -> gx_display_driver_horizontal_pattern_line_draw(context,
257
11110
                                                                              clip_rect.gx_rectangle_left,
258
11110
                                                                              clip_rect.gx_rectangle_right,
259
                                                                              y_start);
260
261
11110
                    if (clip_rect.gx_rectangle_right < x_end)
262
                    {
263
5
                        width = (GX_VALUE)((x_end - clip_rect.gx_rectangle_right) & 0x1F);
264
5
                        if ((context -> gx_draw_context_brush.gx_brush_pattern_mask >> width) == 0)
265
                        {
266
4
                            context -> gx_draw_context_brush.gx_brush_pattern_mask <<= (32 - width);
267
                        }
268
                        else
269
                        {
270
1
                            context -> gx_draw_context_brush.gx_brush_pattern_mask >>= width;
271
                        }
272
                    }
273
                }
274
                else
275
                {
276
                    /* Call display driver's simple horizontal line drawing function.  */
277
2641614
                    display -> gx_display_driver_horizontal_line_draw(context,
278
2641614
                                                                      clip_rect.gx_rectangle_left,
279
2641614
                                                                      clip_rect.gx_rectangle_right,
280
2641614
                                                                      clip_rect.gx_rectangle_top,
281
2641614
                                                                      clip_rect.gx_rectangle_bottom - clip_rect.gx_rectangle_top + 1,
282
                                                                      brush -> gx_brush_line_color);
283
                }
284
            }
285
            else
286
            {
287
3534139
                if (brush -> gx_brush_line_pattern)
288
                {
289
11028
                    if (clip_rect.gx_rectangle_top > y_start)
290
                    {
291
30
                        width = (GX_VALUE)((clip_rect.gx_rectangle_top - y_start) & 0x1F);
292
30
                        context -> gx_draw_context_brush.gx_brush_pattern_mask >>= width;
293
                    }
294
295
                    /* Call display driver's simple vertical line drawing function.  */
296
11028
                    display -> gx_display_driver_vertical_pattern_line_draw(context,
297
11028
                                                                            clip_rect.gx_rectangle_top,
298
11028
                                                                            clip_rect.gx_rectangle_bottom,
299
                                                                            x_start);
300
301
11028
                    if (clip_rect.gx_rectangle_bottom < y_end)
302
                    {
303
25
                        width = (GX_VALUE)((y_end - clip_rect.gx_rectangle_bottom) & 0x1F);
304
25
                        if ((context -> gx_draw_context_brush.gx_brush_pattern_mask >> width) == 0)
305
                        {
306
10
                            context -> gx_draw_context_brush.gx_brush_pattern_mask <<= (32 - width);
307
                        }
308
                        else
309
                        {
310
15
                            context -> gx_draw_context_brush.gx_brush_pattern_mask >>= width;
311
                        }
312
                    }
313
                }
314
                else
315
                {
316
                    /* Call display driver's simple vertical line drawing function.  */
317
3523111
                    display -> gx_display_driver_vertical_line_draw(context,
318
3523111
                                                                    clip_rect.gx_rectangle_top,
319
3523111
                                                                    clip_rect.gx_rectangle_bottom,
320
3523111
                                                                    clip_rect.gx_rectangle_left,
321
3523111
                                                                    clip_rect.gx_rectangle_right - clip_rect.gx_rectangle_left + 1,
322
                                                                    brush -> gx_brush_line_color);
323
                }
324
            }
325
6186863
            view = view -> gx_view_next;
326
6186863
            continue;
327
        }
328
329
330
20016
        if (anti_aliased)
331
        {
332
7981
            if (brush_width == 1)
333
            {
334
1616
                display -> gx_display_driver_anti_aliased_line_draw(context, x_start, y_start, x_end, y_end);
335
            }
336
            else
337
            {
338
6365
                display -> gx_display_driver_anti_aliased_wide_line_draw(context, x_start, y_start, x_end, y_end);
339
            }
340
        }
341
        else
342
        {
343
12035
            if (brush_width == 1)
344
            {
345
3695
                display -> gx_display_driver_simple_line_draw(context, x_start, y_start, x_end, y_end);
346
            }
347
            else
348
            {
349
8340
                display -> gx_display_driver_simple_wide_line_draw(context, x_start, y_start, x_end, y_end);
350
            }
351
        }
352
20016
        view = view -> gx_view_next;
353
    }
354
355
    /* Return successful completion.  */
356
6245963
    return(GX_SUCCESS);
357
}
358