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 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _gx_canvas_rectangle_fill                           PORTABLE C      */
36 /*                                                           6.1          */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Kenneth Maxwell, Microsoft Corporation                              */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    Support function for gx_canvas_rectangle_draw, draw a wide border   */
44 /*    by drawing a filled rectangle.                                      */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    rectangle                             Rectangle specification       */
49 /*                                                                        */
50 /*  OUTPUT                                                                */
51 /*                                                                        */
52 /*    status                                Completion status             */
53 /*                                                                        */
54 /*  CALLS                                                                 */
55 /*                                                                        */
56 /*    _gx_utility_rectangle_overlap_detect  Detect rectangle overlap      */
57 /*    _gx_canvas_line_draw                  Draw a line                   */
58 /*    [gx_display_driver_horizontal_line_draw]                            */
59 /*                                          Display driver horizontal     */
60 /*                                            line draw routine           */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    _gx_canvas_rectangle_draw                                           */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
71 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*                                                                        */
74 /**************************************************************************/
_gx_canvas_rectangle_fill(GX_RECTANGLE * rectangle,GX_COLOR fill_color)75 static UINT  _gx_canvas_rectangle_fill(GX_RECTANGLE *rectangle, GX_COLOR fill_color)
76 {
77 GX_DRAW_CONTEXT *context;
78 GX_DISPLAY      *display;
79 GX_RECTANGLE     fill_rect;
80 GX_RECTANGLE     bound;
81 GX_VIEW         *view;
82 GX_VALUE         rectangle_height;
83 
84     /* pick up current drawing context */
85     context = _gx_system_current_draw_context;
86 
87     /* Check to see if the rectangle overlaps the dirty area.  */
88     if (!_gx_utility_rectangle_overlap_detect(rectangle, &context -> gx_draw_context_dirty, &bound))
89     {
90         /* nothing to draw, return */
91         return GX_SUCCESS;
92     }
93 
94     /* pick up current display driver */
95     display = context -> gx_draw_context_display;
96 
97 
98     /* test to determine if the bounding rectangle overlaps the region we are allowed to draw
99        into. For each view that overlaps the bounding rectangle, do some drawing.
100      */
101     view = context -> gx_draw_context_view_head;
102 
103     while (view)
104     {
105         if (_gx_utility_rectangle_overlap_detect(&bound, &view -> gx_view_rectangle, &fill_rect))
106         {
107             /* Pickup the height.  */
108             rectangle_height = (GX_VALUE)(fill_rect.gx_rectangle_bottom - fill_rect.gx_rectangle_top + 1);
109             context -> gx_draw_context_clip = &fill_rect;
110 
111             display -> gx_display_driver_horizontal_line_draw(context,
112                                                               fill_rect.gx_rectangle_left,
113                                                               fill_rect.gx_rectangle_right,
114                                                               fill_rect.gx_rectangle_top,
115                                                               rectangle_height, fill_color);
116         }
117         view = view -> gx_view_next;
118     }
119 
120     /* Return successful completion.  */
121     return(GX_SUCCESS);
122 }
123 
124 
125 
126 /**************************************************************************/
127 /*                                                                        */
128 /*  FUNCTION                                               RELEASE        */
129 /*                                                                        */
130 /*    _gx_canvas_rectangle_draw                           PORTABLE C      */
131 /*                                                           6.1          */
132 /*  AUTHOR                                                                */
133 /*                                                                        */
134 /*    Kenneth Maxwell, Microsoft Corporation                              */
135 /*                                                                        */
136 /*  DESCRIPTION                                                           */
137 /*                                                                        */
138 /*    This draws the specified rectangle on the current context.          */
139 /*                                                                        */
140 /*  INPUT                                                                 */
141 /*                                                                        */
142 /*    rectangle                             Rectangle specification       */
143 /*                                                                        */
144 /*  OUTPUT                                                                */
145 /*                                                                        */
146 /*    status                                Completion status             */
147 /*                                                                        */
148 /*  CALLS                                                                 */
149 /*                                                                        */
150 /*    _gx_utility_rectangle_overlap_detect  Detect rectangle overlap      */
151 /*    _gx_canvas_line_draw                  Draw a line                   */
152 /*    _gx_canvas_rectangle_draw             Draw a rectangle              */
153 /*    [gx_display_driver_horizontal_line_draw]                            */
154 /*                                          Display driver horizontal     */
155 /*                                            line draw routine           */
156 /*                                                                        */
157 /*  CALLED BY                                                             */
158 /*                                                                        */
159 /*    _gx_scrollbar_draw                                                  */
160 /*    _gx_slider_needle_draw                                              */
161 /*    _gx_widget_border_draw                                              */
162 /*                                                                        */
163 /*  RELEASE HISTORY                                                       */
164 /*                                                                        */
165 /*    DATE              NAME                      DESCRIPTION             */
166 /*                                                                        */
167 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
168 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
169 /*                                            resulting in version 6.1    */
170 /*                                                                        */
171 /**************************************************************************/
_gx_canvas_rectangle_draw(GX_RECTANGLE * rectangle)172 UINT  _gx_canvas_rectangle_draw(GX_RECTANGLE *rectangle)
173 {
174 GX_DRAW_CONTEXT *context;
175 GX_DISPLAY      *display;
176 GX_RECTANGLE     fill_rect;
177 GX_RECTANGLE     bound;
178 GX_VIEW         *view;
179 GX_COLOR         fill_color;
180 GX_VALUE         rectangle_height;
181 GX_VALUE         brush_width;
182 
183     /* pick up current drawing context */
184     context = _gx_system_current_draw_context;
185 
186     /* Check to see if the rectangle overlaps the dirty area.  */
187     if (!_gx_utility_rectangle_overlap_detect(rectangle, &context -> gx_draw_context_dirty, &bound))
188     {
189         /* nothing to draw, return */
190         return GX_SUCCESS;
191     }
192 
193     /* pick up current display driver */
194     display = context -> gx_draw_context_display;
195 
196     /* if the rectangle has a border, call either the line function (for a single-pixel border)
197        or the rectangle functions (for a wide border), then reduce the size of the rectangle
198        we are drawing here
199      */
200 
201     fill_rect = *rectangle;
202     brush_width = context -> gx_draw_context_brush.gx_brush_width;
203 
204     switch (brush_width)
205     {
206     case 0:
207         /* no border */
208         break;
209 
210     case 1:
211         /* thin border */
212         _gx_canvas_line_draw(rectangle -> gx_rectangle_left,
213                              (GX_VALUE)(rectangle -> gx_rectangle_top + 1),
214                              rectangle -> gx_rectangle_left,
215                              (GX_VALUE)(rectangle -> gx_rectangle_bottom - 1));
216 
217         _gx_canvas_line_draw(rectangle -> gx_rectangle_right,
218                              (GX_VALUE)(rectangle -> gx_rectangle_top + 1),
219                              rectangle -> gx_rectangle_right,
220                              (GX_VALUE)(rectangle -> gx_rectangle_bottom - 1));
221 
222         _gx_canvas_line_draw(rectangle -> gx_rectangle_left,
223                              rectangle -> gx_rectangle_top,
224                              rectangle -> gx_rectangle_right,
225                              rectangle -> gx_rectangle_top);
226 
227         _gx_canvas_line_draw(rectangle -> gx_rectangle_left,
228                              rectangle -> gx_rectangle_bottom,
229                              rectangle -> gx_rectangle_right,
230                              rectangle -> gx_rectangle_bottom);
231 
232         fill_rect.gx_rectangle_top = (GX_VALUE)(fill_rect.gx_rectangle_top + 1);
233         fill_rect.gx_rectangle_bottom = (GX_VALUE)(fill_rect.gx_rectangle_bottom - 1);
234         fill_rect.gx_rectangle_left = (GX_VALUE)(fill_rect.gx_rectangle_left + 1);
235         fill_rect.gx_rectangle_right = (GX_VALUE)(fill_rect.gx_rectangle_right - 1);
236         break;
237 
238     default:
239 
240         /* draw the wide top line */
241         fill_rect.gx_rectangle_bottom = (GX_VALUE)(fill_rect.gx_rectangle_top + brush_width - 1);
242         _gx_canvas_rectangle_fill(&fill_rect, context -> gx_draw_context_brush.gx_brush_line_color);
243 
244         /* draw the wide bottom line */
245         fill_rect.gx_rectangle_bottom = rectangle -> gx_rectangle_bottom;
246         fill_rect.gx_rectangle_top = (GX_VALUE)(fill_rect.gx_rectangle_bottom - brush_width + 1);
247         _gx_canvas_rectangle_fill(&fill_rect, context -> gx_draw_context_brush.gx_brush_line_color);
248 
249         /* draw the wide left side */
250         fill_rect.gx_rectangle_top = (GX_VALUE)(rectangle -> gx_rectangle_top + brush_width);
251         fill_rect.gx_rectangle_bottom = (GX_VALUE)(fill_rect.gx_rectangle_bottom - brush_width);
252         fill_rect.gx_rectangle_right = (GX_VALUE)(fill_rect.gx_rectangle_left + brush_width - 1);
253         _gx_canvas_rectangle_fill(&fill_rect, context -> gx_draw_context_brush.gx_brush_line_color);
254 
255         /* draw the wide right side */
256         fill_rect.gx_rectangle_right = rectangle -> gx_rectangle_right;
257         fill_rect.gx_rectangle_left = (GX_VALUE)(fill_rect.gx_rectangle_right - brush_width + 1);
258         _gx_canvas_rectangle_fill(&fill_rect, context -> gx_draw_context_brush.gx_brush_line_color);
259 
260         /* subtract the border from the fill_rect */
261         fill_rect.gx_rectangle_bottom = (GX_VALUE)(rectangle -> gx_rectangle_bottom - brush_width);
262         fill_rect.gx_rectangle_top = (GX_VALUE)(rectangle -> gx_rectangle_top + brush_width);
263         fill_rect.gx_rectangle_left = (GX_VALUE)(rectangle -> gx_rectangle_left + brush_width);
264         fill_rect.gx_rectangle_right = (GX_VALUE)(rectangle -> gx_rectangle_right - brush_width);
265     }
266 
267     if (context -> gx_draw_context_brush.gx_brush_width != 0)
268     {
269         /* Check again, after reducing size, to see if the rectangle overlaps the dirty area.  */
270         if (!_gx_utility_rectangle_overlap_detect(&fill_rect, &context -> gx_draw_context_dirty, &bound))
271         {
272             /* nothing to draw, return */
273             return GX_SUCCESS;
274         }
275     }
276 
277     if ((context -> gx_draw_context_brush.gx_brush_style & GX_BRUSH_SOLID_FILL) == 0)
278     {
279         return GX_SUCCESS;
280     }
281 
282     /* test to determine if the bounding rectangle overlaps the region we are allowed to draw
283        into. For each view that overlaps the bounding rectangle, do some drawing.
284      */
285     view = context -> gx_draw_context_view_head;
286 
287     /* save the fill color for later */
288     fill_color = context -> gx_draw_context_brush.gx_brush_fill_color;
289 
290     while (view)
291     {
292         if (_gx_utility_rectangle_overlap_detect(&bound, &view -> gx_view_rectangle, &fill_rect))
293         {
294             /* Pickup the height.  */
295             rectangle_height = (GX_VALUE)(fill_rect.gx_rectangle_bottom - fill_rect.gx_rectangle_top + 1);
296             context -> gx_draw_context_clip = &fill_rect;
297 
298             display -> gx_display_driver_horizontal_line_draw(context,
299                                                               fill_rect.gx_rectangle_left,
300                                                               fill_rect.gx_rectangle_right,
301                                                               fill_rect.gx_rectangle_top,
302                                                               rectangle_height, fill_color);
303         }
304         view = view -> gx_view_next;
305     }
306 
307     /* Return successful completion.  */
308     return(GX_SUCCESS);
309 }
310 
311