GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_1bpp_simple_line_draw.c Lines: 244 244 100.0 %
Date: 2024-12-05 08:52:37 Branches: 136 136 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_utility.h"
28
#include "gx_display.h"
29
30
/**************************************************************************/
31
/*                                                                        */
32
/*  FUNCTION                                               RELEASE        */
33
/*                                                                        */
34
/*    _gx_display_driver_1bpp_simple_line_draw            PORTABLE C      */
35
/*                                                           6.1          */
36
/*  AUTHOR                                                                */
37
/*                                                                        */
38
/*    Kenneth Maxwell, Microsoft Corporation                              */
39
/*                                                                        */
40
/*  DESCRIPTION                                                           */
41
/*                                                                        */
42
/*    Simple line draw function for the 1bpp display driver.              */
43
/*                                                                        */
44
/*  INPUT                                                                 */
45
/*                                                                        */
46
/*    context                               Drawing context               */
47
/*    xstart                                x-coord of endpoint           */
48
/*    ystart                                y-coord of endpoint           */
49
/*    xend                                  x-coord of endpoint           */
50
/*    yend                                  y-coord of endpoint           */
51
/*                                                                        */
52
/*  OUTPUT                                                                */
53
/*                                                                        */
54
/*    None                                                                */
55
/*                                                                        */
56
/*  CALLS                                                                 */
57
/*                                                                        */
58
/*    GX_ABS                                Compute the absolute value    */
59
/*    GX_SWAP_VALUE                         Swap two values               */
60
/*                                                                        */
61
/*  CALLED BY                                                             */
62
/*                                                                        */
63
/*    GUIX Internal Code                                                  */
64
/*                                                                        */
65
/*  RELEASE HISTORY                                                       */
66
/*                                                                        */
67
/*    DATE              NAME                      DESCRIPTION             */
68
/*                                                                        */
69
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
70
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
71
/*                                            resulting in version 6.1    */
72
/*                                                                        */
73
/**************************************************************************/
74
122
VOID _gx_display_driver_1bpp_simple_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
75
{
76
77
/**************************************************************************/
78
/* Integer non-aliased line draw. This algorithm is taken directly from   */
79
/* Roger Stevens "The C++ graphics programming handbook" pages 281-282.   */
80
/* Removed the pattern test and renamed the variables and converted from  */
81
/* C++ to C. Also modified the algorithm to draw from both ends in to     */
82
/* the middle, instead of drawing from one end to the other.              */
83
/**************************************************************************/
84
85
INT           curx;
86
INT           cury;
87
INT           x_sign;
88
INT           y_sign;
89
INT           decision;
90
INT           nextx;
91
INT           nexty;
92
INT           y_increment;
93
GX_POINT      end_point;
94
GX_POINT      mid_point;
95
GX_RECTANGLE  half_rectangle;
96
GX_RECTANGLE  half_over;
97
INT           sign;
98
INT           steps;
99
INT           pos_start;
100
INT           pos_end;
101
GX_UBYTE      start_mask;
102
GX_UBYTE      end_mask;
103
104
GX_UBYTE     *start_address;
105
GX_UBYTE     *put;
106
GX_UBYTE     *next_put;
107
108
122
GX_BOOL       clipped = GX_TRUE;
109
122
INT           dx = GX_ABS(xend - xstart);
110
122
INT           dy = GX_ABS(yend - ystart);
111
112
122
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
113
122
GX_UBYTE      linecolor = context -> gx_draw_context_brush.gx_brush_line_color & 0x01;
114
INT           stride;
115
116


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