1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
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.1          */
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 /*  RELEASE HISTORY                                                       */
84 /*                                                                        */
85 /*    DATE              NAME                      DESCRIPTION             */
86 /*                                                                        */
87 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
88 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
89 /*                                            resulting in version 6.1    */
90 /*                                                                        */
91 /**************************************************************************/
_gx_canvas_line_draw(GX_VALUE x_start,GX_VALUE y_start,GX_VALUE x_end,GX_VALUE y_end)92 UINT  _gx_canvas_line_draw(GX_VALUE x_start, GX_VALUE y_start, GX_VALUE x_end, GX_VALUE y_end)
93 {
94 GX_DRAW_CONTEXT *context;
95 GX_DISPLAY      *display;
96 GX_RECTANGLE     clip_rect;
97 GX_RECTANGLE     bound;
98 GX_VIEW         *view;
99 GX_BRUSH        *brush;
100 GX_BOOL          simple_line = GX_FALSE;
101 GX_VALUE         width;
102 GX_BOOL          anti_aliased;
103 GX_VALUE         brush_width;
104 
105     /* calculate rectangle that bounds the line. This bounding rectangle
106        is later adjusted based on line width */
107 
108     /* are line coordinates left to right? */
109 
110     if (x_start <= x_end)
111     {
112         /* are line coordinates bottom to top? */
113         if (y_start >= y_end)
114         {
115             _gx_utility_rectangle_define(&bound, x_start, y_end, x_end, y_start);
116         }
117         else
118         {
119             /* line is defined left to right, top to bottom */
120             _gx_utility_rectangle_define(&bound, x_start, y_start, x_end, y_end);
121         }
122     }
123     else
124     {
125         if (y_start >= y_end)
126         {
127             /* line is defined right to left, bottom to top */
128             _gx_utility_rectangle_define(&bound, x_end, y_end, x_start, y_start);
129         }
130         else
131         {
132             /* line is defined right to left, top to bottom */
133             _gx_utility_rectangle_define(&bound, x_end, y_start, x_start, y_end);
134         }
135     }
136 
137     /* pick up the current drawing context */
138     context = _gx_system_current_draw_context;
139     brush = &context -> gx_draw_context_brush;
140     brush_width = brush -> gx_brush_width;
141 
142     if (brush_width == 0)
143     {
144         /* Check brush width. Just return if width is 0. */
145         return(GX_SUCCESS);
146     }
147 
148     if ((brush_width == 1) ||
149         ((brush -> gx_brush_style & GX_BRUSH_ROUND) == 0))
150     {
151         /* If we are drawing a horizontal or vertial line with
152         square line ends, we can do a much simpler and faster
153         line drawing function. Check for these special cases.
154         */
155 
156         /* the brush 1 pixel wide or not round, check for horizontal or vertical */
157         if ((y_start == y_end) || (x_start == x_end))
158         {
159             /* yes, simple line case */
160             simple_line = GX_TRUE;
161         }
162     }
163 
164     /* pick up current display driver */
165     display = context->gx_draw_context_display;
166     /* Angled line using current context brush and canvas: */
167     anti_aliased = GX_FALSE;
168 
169     if (brush -> gx_brush_style & GX_BRUSH_ALIAS)
170     {
171         /* The caller requested an anti-aliased line. Does the driver
172         support it? */
173         if (brush_width == 1)
174         {
175             if (display -> gx_display_driver_anti_aliased_line_draw)
176             {
177                 /* Yes, the driver supports anti-aliased lines, so use them: */
178                 anti_aliased = GX_TRUE;
179             }
180         }
181         else
182         {
183             if (display -> gx_display_driver_anti_aliased_wide_line_draw)
184             {
185                 /* Yes, the driver supports anti-aliased lines, so use them: */
186                 anti_aliased = GX_TRUE;
187             }
188         }
189     }
190 
191     /* We need to expand the bounding rectangle to account for
192        rounded ends and line width > 1
193      */
194     if (simple_line)
195     {
196         if(!brush -> gx_brush_line_pattern)
197         {
198             if (x_start == x_end)
199             {
200                 /* vertical line centered around x coords */
201                 bound.gx_rectangle_left  = (GX_VALUE)(x_start - (brush_width / 2));
202                 bound.gx_rectangle_right = (GX_VALUE)(bound.gx_rectangle_left + brush_width - 1);
203             }
204             else
205             {
206                 /* horizontal line centered around y coords */
207                 bound.gx_rectangle_top = (GX_VALUE)(y_start - (brush_width / 2));
208                 bound.gx_rectangle_bottom = (GX_VALUE)(bound.gx_rectangle_top + brush_width - 1);
209             }
210         }
211     }
212     else
213     {
214         width = (GX_VALUE)((brush_width + 1) / 2);
215 
216         if (anti_aliased)
217         {
218             width = (GX_VALUE)(width + 1);
219         }
220 
221         /* increase the bound by 1/2 the line width */
222         bound.gx_rectangle_top    = (GX_VALUE)(bound.gx_rectangle_top - width);
223         bound.gx_rectangle_left   = (GX_VALUE)(bound.gx_rectangle_left - width);
224         bound.gx_rectangle_right  = (GX_VALUE)(bound.gx_rectangle_right + width);
225         bound.gx_rectangle_bottom = (GX_VALUE)(bound.gx_rectangle_bottom + width);
226     }
227 
228     /* clip the line bounding box to the dirty rectangle */
229     if (!_gx_utility_rectangle_overlap_detect(&bound, &context -> gx_draw_context_dirty, &bound))
230     {
231         /* nothing to draw, return */
232         return GX_SUCCESS;
233     }
234 
235     /* test to determine if the bounding rectangle overlaps the region we are allowed to draw
236        into. For each view that overlaps the bounding rectangle, do some drawing.
237      */
238     view = context -> gx_draw_context_view_head;
239 
240     while (view)
241     {
242         if (!_gx_utility_rectangle_overlap_detect(&view -> gx_view_rectangle, &bound, &clip_rect))
243         {
244             view = view -> gx_view_next;
245             continue;
246         }
247 
248         /* we have a view into which we can draw the line, do it */
249         context -> gx_draw_context_clip = &clip_rect;
250 
251         if (simple_line)
252         {
253             if (y_start == y_end)
254             {
255                 if (brush -> gx_brush_line_pattern)
256                 {
257                     /* Call display driver's simple horizontal pattern line drawing function.  */
258                     display -> gx_display_driver_horizontal_pattern_line_draw(context,
259                                                                               clip_rect.gx_rectangle_left,
260                                                                               clip_rect.gx_rectangle_right,
261                                                                               y_start);
262                 }
263                 else
264                 {
265                     /* Call display driver's simple horizontal line drawing function.  */
266                     display -> gx_display_driver_horizontal_line_draw(context,
267                                                                       clip_rect.gx_rectangle_left,
268                                                                       clip_rect.gx_rectangle_right,
269                                                                       clip_rect.gx_rectangle_top,
270                                                                       clip_rect.gx_rectangle_bottom - clip_rect.gx_rectangle_top + 1,
271                                                                       brush -> gx_brush_line_color);
272                 }
273             }
274             else
275             {
276                 if (brush -> gx_brush_line_pattern)
277                 {
278                     /* Call display driver's simple vertical line drawing function.  */
279                     display -> gx_display_driver_vertical_pattern_line_draw(context,
280                                                                             clip_rect.gx_rectangle_top,
281                                                                             clip_rect.gx_rectangle_bottom,
282                                                                             x_start);
283                 }
284                 else
285                 {
286                     /* Call display driver's simple vertical line drawing function.  */
287                     display -> gx_display_driver_vertical_line_draw(context,
288                                                                     clip_rect.gx_rectangle_top,
289                                                                     clip_rect.gx_rectangle_bottom,
290                                                                     clip_rect.gx_rectangle_left,
291                                                                     clip_rect.gx_rectangle_right - clip_rect.gx_rectangle_left + 1,
292                                                                     brush -> gx_brush_line_color);
293                 }
294             }
295             view = view -> gx_view_next;
296             continue;
297         }
298 
299 
300         if (anti_aliased)
301         {
302             if (brush_width == 1)
303             {
304                 display -> gx_display_driver_anti_aliased_line_draw(context, x_start, y_start, x_end, y_end);
305             }
306             else
307             {
308                 display -> gx_display_driver_anti_aliased_wide_line_draw(context, x_start, y_start, x_end, y_end);
309             }
310         }
311         else
312         {
313             if (brush_width == 1)
314             {
315                 display -> gx_display_driver_simple_line_draw(context, x_start, y_start, x_end, y_end);
316             }
317             else
318             {
319                 display -> gx_display_driver_simple_wide_line_draw(context, x_start, y_start, x_end, y_end);
320             }
321         }
322         view = view -> gx_view_next;
323     }
324 
325     /* Return successful completion.  */
326     return(GX_SUCCESS);
327 }
328 
329