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

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