GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_4bpp_simple_line_draw.c Lines: 267 267 100.0 %
Date: 2026-03-06 19:21:09 Branches: 140 140 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
/**   Display Management (Display)                                        */
19
/**                                                                       */
20
/**************************************************************************/
21
22
#define GX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "gx_api.h"
28
#include "gx_utility.h"
29
#include "gx_display.h"
30
31
/**************************************************************************/
32
/*                                                                        */
33
/*  FUNCTION                                               RELEASE        */
34
/*                                                                        */
35
/*    _gx_display_driver_4bpp_simple_line_draw            PORTABLE C      */
36
/*                                                           6.1          */
37
/*  AUTHOR                                                                */
38
/*                                                                        */
39
/*    Kenneth Maxwell, Microsoft Corporation                              */
40
/*                                                                        */
41
/*  DESCRIPTION                                                           */
42
/*                                                                        */
43
/*    Simple line draw function for the 4bpp display driver.              */
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_ABS                                Compute the absolute value    */
60
/*    GX_SWAP_VALUE                         Swap two values               */
61
/*                                                                        */
62
/*  CALLED BY                                                             */
63
/*                                                                        */
64
/*    GUIX Internal Code                                                  */
65
/*                                                                        */
66
/**************************************************************************/
67
61
VOID _gx_display_driver_4bpp_simple_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
68
{
69
70
/**************************************************************************/
71
/* Integer non-aliased line draw. This algorithm is taken directly from   */
72
/* Roger Stevens "The C++ graphics programming handbook" pages 281-282.   */
73
/* Removed the pattern test and renamed the variables and converted from  */
74
/* C++ to C. Also modified the algorithm to draw from both ends in to     */
75
/* the middle, instead of drawing from one end to the other.              */
76
/**************************************************************************/
77
78
INT           curx;
79
INT           cury;
80
INT           x_sign;
81
INT           y_sign;
82
INT           decision;
83
INT           nextx;
84
INT           nexty;
85
INT           y_increment;
86
GX_POINT      end_point;
87
GX_POINT      mid_point;
88
GX_RECTANGLE  half_rectangle;
89
GX_RECTANGLE  half_over;
90
INT           sign;
91
INT           steps;
92
INT           pos_start;
93
INT           pos_end;
94
GX_UBYTE      start_mask;
95
GX_UBYTE      end_mask;
96
GX_UBYTE     *start_address;
97
GX_UBYTE     *put;
98
GX_UBYTE     *next_put;
99
61
GX_BOOL       clipped = GX_TRUE;
100
61
INT           dx = GX_ABS(xend - xstart);
101
61
INT           dy = GX_ABS(yend - ystart);
102
103
61
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
104
61
GX_UBYTE      linecolor = context -> gx_draw_context_brush.gx_brush_line_color & 0x0f;
105
61
GX_UBYTE      color = linecolor;
106
INT           stride;
107
108


61
    if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
109
    {
110
29
        GX_SWAP_VALS(xend, xstart);
111
29
        GX_SWAP_VALS(yend, ystart);
112
    }
113
61
    x_sign = (xend - xstart) / dx;
114
61
    y_sign = (yend - ystart) / dy;
115
116
61
    if (y_sign > 0)
117
    {
118
46
        y_increment = context -> gx_draw_context_pitch;
119
    }
120
    else
121
    {
122
15
        y_increment = 0 - context -> gx_draw_context_pitch;
123
    }
124
125
61
    stride = (context -> gx_draw_context_pitch + 1) >> 1;
126
127
61
    start_address = (GX_UBYTE *)(context -> gx_draw_context_memory);
128
61
    pos_start = ystart * (stride << 1) + xstart;
129
61
    pos_end = yend * (stride << 1) + xend;
130
131
61
    end_point.gx_point_x = (GX_VALUE)xstart;
132
61
    end_point.gx_point_y = (GX_VALUE)ystart;
133
134
61
    if (_gx_utility_rectangle_point_detect(clip, end_point))
135
    {
136
34
        end_point.gx_point_x = (GX_VALUE)xend;
137
34
        end_point.gx_point_y = (GX_VALUE)yend;
138
139
34
        if (_gx_utility_rectangle_point_detect(clip, end_point))
140
        {
141
16
            clipped = GX_FALSE;
142
        }
143
    }
144
145
61
    if (clipped)
146
    {
147
        /* here if we must do clipping in the inner loop, because one
148
           or both of the end points are outside clipping rectangle */
149
150
        /* Calculate the middle point of the line.  */
151
45
        mid_point.gx_point_x = (GX_VALUE)((xend + xstart) >> 1);
152
45
        mid_point.gx_point_y = (GX_VALUE)((yend + ystart) >> 1);
153
154
        /* Judge the clip in which side.  */
155
45
        if (_gx_utility_rectangle_point_detect(clip, mid_point))
156
        {
157
158
            /* the clip in two sides.  */
159
24
            if (dx >= dy)
160
            {
161
                /* walk out the clipping point.  */
162
271
                for (curx = xstart, cury = ystart, decision = (dx >> 1); curx < mid_point.gx_point_x;
163
259
                     curx++, decision += dy)
164
                {
165
270
                    if (decision >= dx)
166
                    {
167
149
                        decision -= dx;
168
149
                        cury += y_sign;
169
170
149
                        pos_start += y_increment;
171
                    }
172
173
270
                    if (curx >= clip -> gx_rectangle_left &&
174
263
                        cury >= clip -> gx_rectangle_top &&
175
217
                        cury <= clip -> gx_rectangle_bottom)
176
                    {
177
11
                        break;
178
                    }
179
259
                    pos_start++;
180
                }
181
463
                for (; curx <= mid_point.gx_point_x;
182
451
                     curx++, decision += dy)
183
                {
184
451
                    if (decision >= dx)
185
                    {
186
243
                        decision -= dx;
187
243
                        cury += y_sign;
188
243
                        pos_start += y_increment;
189
                    }
190
451
                    put = start_address;
191
451
                    put += pos_start >> 1;
192
451
                    if (pos_start & 0x01)
193
                    {
194
228
                        start_mask = 0x0f;
195
228
                        color = linecolor;
196
                    }
197
                    else
198
                    {
199
223
                        start_mask = 0xf0;
200
223
                        color = (GX_UBYTE)(linecolor << 4);
201
                    }
202
451
                    *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
203
451
                    pos_start++;
204
                }
205
541
                for (nextx = xend, nexty = yend, decision = (dx >> 1); nextx > mid_point.gx_point_x;
206
529
                     nextx--, decision += dy)
207
                {
208
540
                    if (decision >= dx)
209
                    {
210
303
                        decision -= dx;
211
303
                        nexty -= y_sign;
212
303
                        pos_end -= y_increment;
213
                    }
214
540
                    if (nextx <= clip -> gx_rectangle_right &&
215
48
                        nexty >= clip -> gx_rectangle_top &&
216
31
                        nexty <= clip -> gx_rectangle_bottom)
217
                    {
218
11
                        break;
219
                    }
220
529
                    pos_end--;
221
                }
222
223
182
                for (; nextx > mid_point.gx_point_x;
224
170
                     nextx--, decision += dy)
225
                {
226
170
                    if (decision >= dx)
227
                    {
228
79
                        decision -= dx;
229
79
                        nexty -= y_sign;
230
79
                        pos_end -= y_increment;
231
                    }
232
170
                    next_put = start_address;
233
170
                    next_put += pos_end >> 1;
234
170
                    if (pos_end & 0x01)
235
                    {
236
84
                        end_mask = 0x0f;
237
84
                        color = linecolor;
238
                    }
239
                    else
240
                    {
241
86
                        end_mask = 0xf0;
242
86
                        color = (GX_UBYTE)(linecolor << 4);
243
                    }
244
170
                    *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
245
170
                    pos_end--;
246
                }
247
            }
248
            else
249
            {
250
561
                for (nextx = xend, nexty = yend, decision = (dy >> 1); nexty > mid_point.gx_point_y;
251
549
                     nexty--, decision += dx)
252
                {
253
560
                    if (decision >= dy)
254
                    {
255
304
                        decision -= dy;
256
304
                        nextx -= x_sign;
257
304
                        pos_end -= x_sign;
258
                    }
259
560
                    if (nextx >= clip -> gx_rectangle_left &&
260
519
                        nextx <= clip -> gx_rectangle_right &&
261
313
                        nexty <= clip -> gx_rectangle_bottom)
262
                    {
263
11
                        break;
264
                    }
265
549
                    pos_end -= context -> gx_draw_context_pitch;
266
                }
267
268
211
                for (; nexty > mid_point.gx_point_y;
269
199
                     nexty--, decision += dx)
270
                {
271
199
                    if (decision >= dy)
272
                    {
273
87
                        decision -= dy;
274
87
                        nextx -= x_sign;
275
87
                        pos_end -= x_sign;
276
                    }
277
199
                    next_put = start_address;
278
199
                    next_put += pos_end >> 1;
279
199
                    if (pos_end & 0x01)
280
                    {
281
91
                        end_mask = 0x0f;
282
91
                        color = linecolor;
283
                    }
284
                    else
285
                    {
286
108
                        end_mask = 0xf0;
287
108
                        color = (GX_UBYTE)(linecolor << 4);
288
                    }
289
199
                    *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
290
199
                    pos_end -= context -> gx_draw_context_pitch;
291
                }
292
293
                /* walk out the clipping point.  */
294
272
                for (curx = xstart, cury = ystart, decision = (dy >> 1); cury < mid_point.gx_point_y;
295
260
                     cury++, decision += dx)
296
                {
297
271
                    if (decision >= dy)
298
                    {
299
149
                        decision -= dy;
300
149
                        curx += x_sign;
301
149
                        pos_start += x_sign;
302
                    }
303
304
271
                    if (curx >= clip -> gx_rectangle_left &&
305
253
                        curx <= clip -> gx_rectangle_right &&
306
47
                        cury >= clip -> gx_rectangle_top)
307
                    {
308
11
                        break;
309
                    }
310
260
                    pos_start += context -> gx_draw_context_pitch;
311
                }
312
509
                for (; cury <= mid_point.gx_point_y;
313
497
                     cury++, decision += dx)
314
                {
315
497
                    if (decision >= dy)
316
                    {
317
250
                        decision -= dy;
318
250
                        curx += x_sign;
319
250
                        pos_start += x_sign;
320
                    }
321
497
                    put = start_address;
322
497
                    put += pos_start >> 1;
323
497
                    if (pos_start & 0x01)
324
                    {
325
241
                        start_mask = 0x0f;
326
241
                        color = linecolor;
327
                    }
328
                    else
329
                    {
330
256
                        start_mask = 0xf0;
331
256
                        color = (GX_UBYTE)(linecolor << 4);
332
                    }
333
497
                    *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
334
497
                    pos_start += context -> gx_draw_context_pitch;
335
                }
336
            }
337
        }
338
        else
339
        {
340
            /* The clip stay at one side.  */
341
21
            if (dx >= dy)
342
            {
343
11
                half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
344
11
                half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
345
11
                if (y_sign == 1)
346
                {
347
5
                    half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
348
5
                    half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
349
                }
350
                else
351
                {
352
6
                    half_rectangle.gx_rectangle_top = mid_point.gx_point_y;
353
6
                    half_rectangle.gx_rectangle_bottom = (GX_VALUE)ystart;
354
                }
355
356
11
                if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
357
                {
358
7
                    curx = xstart;
359
7
                    cury = ystart;
360
7
                    steps = mid_point.gx_point_x - curx + 1;
361
7
                    sign = 1;
362
                }
363
                else
364
                {
365
4
                    curx = xend;
366
4
                    cury = yend;
367
4
                    steps = xend - mid_point.gx_point_x;
368
4
                    sign = -1;
369
4
                    y_increment = 0 - y_increment;
370
4
                    y_sign = 0 - y_sign;
371
4
                    pos_start = pos_end;
372
                }
373
951
                for (decision = (dx >> 1); steps > 0; curx += sign, decision += dy, steps--)
374
                {
375
940
                    if (decision >= dx)
376
                    {
377
426
                        decision -= dx;
378
426
                        cury += y_sign;
379
426
                        pos_start += y_increment;
380
                    }
381
382
940
                    if (curx >= clip -> gx_rectangle_left &&
383
934
                        curx <= clip -> gx_rectangle_right &&
384
458
                        cury >= clip -> gx_rectangle_top &&
385
415
                        cury <= clip -> gx_rectangle_bottom)
386
                    {
387
399
                        put = start_address;
388
399
                        put += pos_start >> 1;
389
399
                        if (pos_start & 0x01)
390
                        {
391
198
                            start_mask = 0x0f;
392
198
                            color = linecolor;
393
                        }
394
                        else
395
                        {
396
201
                            start_mask = 0xf0;
397
201
                            color = (GX_UBYTE)(linecolor << 4);
398
                        }
399
399
                        *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
400
                    }
401
940
                    pos_start += sign;
402
                }
403
            }
404
            else
405
            {
406
10
                half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
407
10
                half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
408
10
                if (x_sign == 1)
409
                {
410
5
                    half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
411
5
                    half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
412
                }
413
                else
414
                {
415
5
                    half_rectangle.gx_rectangle_right = (GX_VALUE)xstart;
416
5
                    half_rectangle.gx_rectangle_left = mid_point.gx_point_x;
417
                }
418
419
10
                if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
420
                {
421
5
                    curx = xstart;
422
5
                    cury = ystart;
423
5
                    steps = mid_point.gx_point_y - cury + 1;
424
5
                    y_increment = context -> gx_draw_context_pitch;
425
5
                    sign = 1;
426
                }
427
                else
428
                {
429
5
                    curx = xend;
430
5
                    cury = yend;
431
5
                    steps = yend - mid_point.gx_point_y;
432
5
                    sign = -1;
433
5
                    y_increment = 0 - context -> gx_draw_context_pitch;
434
5
                    x_sign = 0 - x_sign;
435
5
                    pos_start = pos_end;
436
                }
437
438
769
                for (decision = (dy >> 1); steps > 0; cury += sign, decision += dx, steps--)
439
                {
440
759
                    if (decision >= dy)
441
                    {
442
402
                        decision -= dy;
443
402
                        curx += x_sign;
444
402
                        pos_start += x_sign;
445
                    }
446
759
                    if (curx >= clip -> gx_rectangle_left &&
447
754
                        curx <= clip -> gx_rectangle_right &&
448
650
                        cury >= clip -> gx_rectangle_top &&
449
614
                        cury <= clip -> gx_rectangle_bottom)
450
                    {
451
336
                        put = start_address;
452
336
                        put += pos_start >> 1;
453
336
                        if (pos_start & 0x01)
454
                        {
455
160
                            start_mask = 0x0f;
456
160
                            color = linecolor;
457
                        }
458
                        else
459
                        {
460
176
                            start_mask = 0xf0;
461
176
                            color = (GX_UBYTE)(linecolor << 4);
462
                        }
463
336
                        *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
464
                    }
465
759
                    pos_start += y_increment;
466
                }
467
            }
468
        }
469
    }
470
    else
471
    {
472
        /* here if both line ends lie within clipping rectangle, we can
473
           run a faster inner loop */
474
16
        if (dx >= dy)
475
        {
476
12
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
477
704
                 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
478
692
                 decision += dy)
479
            {
480
481
692
                if (decision >= dx)
482
                {
483
676
                    decision -= dx;
484
676
                    cury += y_sign;
485
676
                    nexty -= y_sign;
486
487
676
                    pos_start += y_increment;
488
676
                    pos_end -= y_increment;
489
                }
490
692
                put = start_address;
491
692
                put += pos_start >> 1;
492
692
                if (pos_start & 0x01)
493
                {
494
348
                    start_mask = 0x0f;
495
348
                    color = linecolor;
496
                }
497
                else
498
                {
499
344
                    start_mask = 0xf0;
500
344
                    color = (GX_UBYTE)(linecolor << 4);
501
                }
502
692
                *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
503
692
                next_put = start_address;
504
692
                next_put += pos_end >> 1;
505
692
                if (pos_end & 0x01)
506
                {
507
348
                    end_mask = 0x0f;
508
348
                    color = linecolor;
509
                }
510
                else
511
                {
512
344
                    end_mask = 0xf0;
513
344
                    color = (GX_UBYTE)(linecolor << 4);
514
                }
515
692
                *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
516
692
                pos_start++;
517
692
                pos_end--;
518
            }
519
        }
520
        else
521
        {
522
4
            for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
523
236
                 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
524
232
                 decision += dx)
525
            {
526
232
                if (decision >= dy)
527
                {
528
224
                    decision -= dy;
529
224
                    curx += x_sign;
530
224
                    nextx -= x_sign;
531
532
224
                    pos_start += x_sign;
533
224
                    pos_end -= x_sign;
534
                }
535
232
                put = start_address;
536
232
                put += pos_start >> 1;
537
232
                if (pos_start & 0x01)
538
                {
539
120
                    start_mask = 0x0f;
540
120
                    color = linecolor;
541
                }
542
                else
543
                {
544
112
                    start_mask = 0xf0;
545
112
                    color = (GX_UBYTE)(linecolor << 4);
546
                }
547
232
                *put = (GX_UBYTE)((GX_UBYTE)((*put) & (~start_mask)) | color);
548
232
                next_put = start_address;
549
232
                next_put += pos_end >> 1;
550
232
                if (pos_end & 0x01)
551
                {
552
120
                    end_mask = 0x0f;
553
120
                    color = linecolor;
554
                }
555
                else
556
                {
557
112
                    end_mask = 0xf0;
558
112
                    color = (GX_UBYTE)(linecolor << 4);
559
                }
560
232
                *next_put = (GX_UBYTE)((GX_UBYTE)((*next_put) & (~end_mask)) | color);
561
562
232
                pos_start += context -> gx_draw_context_pitch;
563
232
                pos_end -= context -> gx_draw_context_pitch;
564
            }
565
        }
566
    }
567
61
}
568