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 /**   System Management (System)                                          */
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_canvas.h"
29 #include "gx_widget.h"
30 #include "gx_utility.h"
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _gx_system_canvas_draw_partial_canvas               PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Ting Zhu, Microsoft Corporation                                     */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function draws the dirty area of the specified canvas with     */
45 /*    partial canvas buffer and toggle the dirty area to the display or   */
46 /*    a composite canvas.                                                 */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    None                                                                */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _gx_system_dirty_list_trim            Trim dirty area list          */
59 /*    _gx_canvas_drawing_initiate           Initiate drawing on canvas    */
60 /*    _gx_widget_children_draw              Draw widgets children         */
61 /*    [gx_widget_draw_function]             Call widget's drawing function*/
62 /*    _gx_canvas_drawing_complete           Complete drawing on canvas    */
63 /*    _gx_system_canvas_toggle              Toggle the frame buffer       */
64 /*    _gx_utility_rectangle_shift           Shift a rectangle             */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    _gx_system_canvas_refresh                                           */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  10-31-2023     Ting Zhu                 Initial Version 6.3.0         */
75 /*                                                                        */
76 /**************************************************************************/
77 #ifdef GX_ENABLE_CANVAS_PARTIAL_FRAME_BUFFER
_gx_system_canvas_draw_partial_canvas(GX_WINDOW_ROOT * root)78 static UINT _gx_system_canvas_draw_partial_canvas(GX_WINDOW_ROOT *root)
79 {
80 UINT           status = GX_SUCCESS;
81 GX_RECTANGLE   dirty_sum;
82 GX_RECTANGLE   dirty_frame;
83 UINT           index;
84 GX_WIDGET     *drawit;
85 GX_DIRTY_AREA *dirty_list_entry;
86 GX_CANVAS     *canvas = root -> gx_window_root_canvas;
87 GX_VALUE       dirty_width;
88 GX_VALUE       dirty_height;
89 
90 #if defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL) || defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
91 GX_RECTANGLE dirty_mask;
92 
93     if (_gx_system_dirty_list_trim(&dirty_sum, root) == GX_FALSE)
94     {
95         return GX_SUCCESS;
96     }
97 
98     dirty_mask = dirty_sum;
99 #endif
100 
101     /* Refresh canvas in the dirty area.  */
102     if (canvas -> gx_canvas_draw_count > 0)
103     {
104         _gx_system_dirty_partial_add((GX_WIDGET *)root, &canvas -> gx_canvas_dirty_area);
105         canvas -> gx_canvas_draw_count = 0;
106     }
107 
108 #if defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL)
109     dirty_height = (GX_VALUE)(dirty_sum.gx_rectangle_bottom - dirty_sum.gx_rectangle_top + 1);
110     dirty_width = (GX_VALUE)(canvas -> gx_canvas_memory_size / canvas -> gx_canvas_display -> gx_display_driver_row_pitch_get((USHORT)dirty_height));
111     dirty_width = (GX_VALUE)(dirty_width & 0xFFFC);
112     dirty_mask.gx_rectangle_right = (GX_VALUE)(dirty_mask.gx_rectangle_left + dirty_width - 1);
113 
114     while (dirty_mask.gx_rectangle_left <= dirty_sum.gx_rectangle_right)
115     {
116         if (dirty_mask.gx_rectangle_right > dirty_sum.gx_rectangle_right)
117         {
118             dirty_mask.gx_rectangle_right = dirty_sum.gx_rectangle_right;
119         }
120 #elif defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
121     dirty_width = (GX_VALUE)(dirty_sum.gx_rectangle_right - dirty_sum.gx_rectangle_left + 1);
122     dirty_height = (GX_VALUE)(canvas -> gx_canvas_memory_size / canvas -> gx_canvas_display -> gx_display_driver_row_pitch_get((USHORT)((dirty_width + 3) & 0xFFFC)));
123     dirty_mask.gx_rectangle_bottom = (GX_VALUE)(dirty_mask.gx_rectangle_top + dirty_height - 1);
124 
125     while (dirty_mask.gx_rectangle_top <= dirty_sum.gx_rectangle_bottom)
126     {
127         if (dirty_mask.gx_rectangle_bottom > dirty_sum.gx_rectangle_bottom)
128         {
129             dirty_mask.gx_rectangle_bottom = dirty_sum.gx_rectangle_bottom;
130         }
131 #endif
132 
133         /* Initialize dirty area pointers.  */
134         dirty_list_entry = canvas -> gx_canvas_dirty_list;
135 
136         /* Loop through dirty areas to redraw as needed.  */
137         for (index = 0; index < canvas -> gx_canvas_dirty_count; index++)
138         {
139             /* Pickup widget associated with dirty area.  */
140             drawit = dirty_list_entry -> gx_dirty_area_widget;
141 
142             /* Is the widget pointer valid?  */
143 
144             if (drawit && (drawit -> gx_widget_status & GX_STATUS_VISIBLE))
145             {
146                 /* if the object is transparent, we need to draw the parent.
147                     This should not happen, because dircty_partial_add checks
148                     for transparency, but just for safety we test again here  */
149 
150                 if (drawit -> gx_widget_status & GX_STATUS_TRANSPARENT ||
151                     drawit -> gx_widget_style & (GX_STYLE_BORDER_RAISED | GX_STYLE_BORDER_RECESSED))
152                 {
153                     while (drawit -> gx_widget_parent)
154                     {
155                         drawit = drawit -> gx_widget_parent;
156 
157                         if (!(drawit -> gx_widget_status & GX_STATUS_TRANSPARENT))
158                         {
159                             /* we need to start drawing at this non-transparent
160                                 background widget */
161 
162                             drawit -> gx_widget_status |= GX_STATUS_DIRTY;
163                             break;
164                         }
165                     }
166                 }
167 
168 #if defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL) || defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
169                 if (_gx_utility_rectangle_overlap_detect(&dirty_list_entry -> gx_dirty_area_rectangle, &dirty_mask, &dirty_frame) == GX_TRUE &&
170                     _gx_utility_rectangle_overlap_detect(&dirty_frame, &drawit -> gx_widget_clip, &dirty_frame) == GX_TRUE)
171                 {
172 #else
173                 dirty_sum = dirty_list_entry -> gx_dirty_area_rectangle;
174                 if (_gx_utility_rectangle_overlap_detect(&dirty_sum, &drawit -> gx_widget_clip, &dirty_sum) == GX_TRUE)
175                 {
176                     dirty_frame = dirty_sum;
177 
178                     /* Split dirty area into small pieces.  */
179                     dirty_width = (GX_VALUE)(dirty_frame.gx_rectangle_right - dirty_frame.gx_rectangle_left + 1);
180                     dirty_height = (GX_VALUE)(canvas -> gx_canvas_memory_size / canvas -> gx_canvas_display -> gx_display_driver_row_pitch_get((USHORT)((dirty_width + 3) & 0xFFFC)));
181                     dirty_frame.gx_rectangle_bottom = (GX_VALUE)(dirty_frame.gx_rectangle_top + dirty_height - 1);
182 
183                     while (dirty_frame.gx_rectangle_top <= dirty_sum.gx_rectangle_bottom)
184                     {
185                         if (dirty_frame.gx_rectangle_bottom > dirty_sum.gx_rectangle_bottom)
186                         {
187                             dirty_frame.gx_rectangle_bottom = dirty_sum.gx_rectangle_bottom;
188                         }
189 #endif
190 
191                     /* Initiate drawing on this canvas.  */
192                     status = _gx_canvas_drawing_initiate(canvas, drawit, &dirty_frame);
193 
194                     if (status == GX_NO_VIEWS)
195                     {
196                         /* If we are attempting to draw the root window and it has no views,
197                             just draw the children of the root */
198 
199                         if (drawit -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
200                         {
201                             _gx_widget_children_draw(drawit);
202                         }
203                     }
204                     else
205                     {
206                         drawit -> gx_widget_draw_function(drawit);
207                     }
208 
209                     /* Indicate that drawing on this canvas is complete.  */
210                     _gx_canvas_drawing_complete(canvas, GX_TRUE);
211 
212 #if !defined(GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL) && !defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
213                     _gx_utility_rectangle_shift(&dirty_frame, 0, dirty_height);
214                 }
215 #endif
216             }
217         }
218 
219         /* Move to the next dirty area.  */
220         dirty_list_entry++;
221     }
222 
223 #ifdef GX_CANVAS_REFRESH_DIRECTION_HORIZONTAL
224     _gx_utility_rectangle_shift(&dirty_mask, dirty_width, 0);
225 }
226 #elif defined(GX_CANVAS_REFRESH_DIRECTION_VERTICAL)
227     _gx_utility_rectangle_shift(&dirty_mask, 0, dirty_height);
228 }
229 #endif
230 
231 canvas -> gx_canvas_dirty_count = 0;
232 
233 return GX_SUCCESS;
234 }
235 #endif
236 
237 /**************************************************************************/
238 /*                                                                        */
239 /*  FUNCTION                                               RELEASE        */
240 /*                                                                        */
241 /*    _gx_system_canvas_refresh                           PORTABLE C      */
242 /*                                                           6.3.0        */
243 /*  AUTHOR                                                                */
244 /*                                                                        */
245 /*    Kenneth Maxwell, Microsoft Corporation                              */
246 /*                                                                        */
247 /*  DESCRIPTION                                                           */
248 /*                                                                        */
249 /*    This function refreshes the screen(s) of GUIX.                      */
250 /*                                                                        */
251 /*  INPUT                                                                 */
252 /*                                                                        */
253 /*    None                                                                */
254 /*                                                                        */
255 /*  OUTPUT                                                                */
256 /*                                                                        */
257 /*    None                                                                */
258 /*                                                                        */
259 /*  CALLS                                                                 */
260 /*                                                                        */
261 /*    GX_ENTER_CRITICAL                     Enter GUIX critical section   */
262 /*    _gx_system_views_update               Update views                  */
263 /*    _gx_system_dirty_list_trim            Trim dirty area list          */
264 /*    _gx_canvas_drawing_initiate           Initiate drawing on canvas    */
265 /*    _gx_widget_children_draw              Draw widgets children         */
266 /*    [gx_widget_draw_function]             Call widget's drawing function*/
267 /*    _gx_canvas_drawing_complete           Complete drawing on canvas    */
268 /*    _gx_canvas_composite_create           Create a canvas composite     */
269 /*    [gx_display_driver_buffer_toggle]     Toggle the frame buffer       */
270 /*    GX_EXIT_CRITICAL                      Exit GUIX critical section    */
271 /*                                                                        */
272 /*  CALLED BY                                                             */
273 /*                                                                        */
274 /*    GUIX Internal Code                                                  */
275 /*                                                                        */
276 /*  RELEASE HISTORY                                                       */
277 /*                                                                        */
278 /*    DATE              NAME                      DESCRIPTION             */
279 /*                                                                        */
280 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
281 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
282 /*                                            resulting in version 6.1    */
283 /*  10-31-2023     Ting Zhu                 Modified comment(s),          */
284 /*                                            added partial canvas buffer */
285 /*                                            support,                    */
286 /*                                            resulting in version 6.3.0  */
287 /*                                                                        */
288 /**************************************************************************/
289 UINT  _gx_system_canvas_refresh(VOID)
290 {
291 UINT            status = GX_SUCCESS;
292 UINT            index;
293 GX_DIRTY_AREA  *dirty;
294 GX_WIDGET      *drawit;
295 GX_CANVAS      *canvas;
296 GX_RECTANGLE    dirty_sum;
297 GX_WINDOW_ROOT *root;
298 
299     /* Determine if there are no canvas or screens created.  */
300     if (!_gx_system_canvas_created_list)
301     {
302         return GX_INVALID_CANVAS;
303     }
304 
305     /* lock access to GUIX */
306     GX_ENTER_CRITICAL
307 
308     canvas = GX_NULL;
309 
310     /* check to see if viewports need to be recalculated */
311     root = _gx_system_root_window_created_list;
312 
313     while (root)
314     {
315         if (!(root -> gx_widget_status & GX_STATUS_VISIBLE))
316         {
317             root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
318             continue;
319         }
320 
321         if (root -> gx_window_root_views_changed)
322         {
323             _gx_system_views_update(root);
324         }
325 
326         /* pick up the canvas pointer */
327         canvas = root -> gx_window_root_canvas;
328 
329 #ifdef GX_ENABLE_CANVAS_PARTIAL_FRAME_BUFFER
330         if (canvas -> gx_canvas_status & GX_CANVAS_PARTIAL_FRAME_BUFFER)
331         {
332             _gx_system_canvas_draw_partial_canvas(root);
333             root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
334             continue;
335         }
336 #endif
337 
338         /* Trim any redundant dirty areas prior to doing the update.  */
339         if (_gx_system_dirty_list_trim(&dirty_sum, root))
340         {
341             /* Initiate drawing on this canvas.  */
342             _gx_canvas_drawing_initiate(canvas, (GX_WIDGET *)root, &dirty_sum);
343 
344             /* Initialize dirty area pointers.  */
345             dirty = canvas -> gx_canvas_dirty_list;
346 
347             /* Loop through dirty areas to redraw as needed.  */
348             for (index = 0; index < canvas -> gx_canvas_dirty_count; index++)
349             {
350                 /* Pickup widget associated with dirty area.  */
351                 drawit = dirty -> gx_dirty_area_widget;
352 
353                 /* Is the widget pointer valid?  */
354 
355                 if (drawit)
356                 {
357                     /* if the object is transparent, we need to draw the parent.
358                        This should not happen, because dircty_partial_add checks
359                        for transparency, but just for safety we test again here  */
360 
361                     if (drawit -> gx_widget_status & GX_STATUS_TRANSPARENT)
362                     {
363                         while (drawit -> gx_widget_parent)
364                         {
365                             drawit = drawit -> gx_widget_parent;
366 
367                             if (!(drawit -> gx_widget_status & GX_STATUS_TRANSPARENT))
368                             {
369                                 /* we need to start drawing at this non-transparent
370                                    background widget */
371 
372                                 drawit -> gx_widget_status |= GX_STATUS_DIRTY;
373                                 break;
374                             }
375                         }
376                     }
377 
378                     /* Initiate drawing on this canvas.  */
379 
380                     status = _gx_canvas_drawing_initiate(canvas, drawit,
381                                                          &dirty -> gx_dirty_area_rectangle);
382 
383                     if (status == GX_NO_VIEWS)
384                     {
385                         /* If we are attempting to draw the root window and it has no views,
386                            just draw the children of the root */
387 
388                         if (drawit -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
389                         {
390                             _gx_widget_children_draw(drawit);
391                         }
392                     }
393                     else
394                     {
395                         drawit -> gx_widget_draw_function(drawit);
396                     }
397 
398                     /* Indicate that drawing on this canvas is complete.  */
399                     _gx_canvas_drawing_complete(canvas, GX_FALSE);
400                 }
401                 /* Move to the next dirty area.  */
402                 dirty++;
403             }
404             /* Indicate that drawing on this canvas is complete.  */
405             _gx_canvas_drawing_complete(canvas, GX_FALSE);
406         }
407         root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
408     }
409 
410     /* if compositing is enabled, create the composite here, rather than
411        in the driver. Most of the code is common */
412 
413     if (_gx_canvas_composite_create(&canvas))
414     {
415         if (canvas -> gx_canvas_draw_count > 0)
416         {
417             canvas -> gx_canvas_display -> gx_display_driver_buffer_toggle(canvas, &canvas -> gx_canvas_dirty_area);
418             canvas -> gx_canvas_draw_count = 0;
419         }
420     }
421     else
422     {
423         /* Reset the dirty area counts  */
424         root = _gx_system_root_window_created_list;
425 
426         while (root)
427         {
428             canvas = root -> gx_window_root_canvas;
429 
430             /* reset the canvas dirty counter */
431             canvas -> gx_canvas_dirty_count = 0;
432 
433             if (root -> gx_widget_status & GX_STATUS_VISIBLE)
434             {
435                 if (canvas -> gx_canvas_draw_count > 0)
436                 {
437                     /* Call the driver buffer toggle function for this canvas.  */
438 
439                     if ((canvas -> gx_canvas_status & GX_CANVAS_MANAGED_VISIBLE) == GX_CANVAS_MANAGED_VISIBLE)
440                     {
441                         canvas -> gx_canvas_display -> gx_display_driver_buffer_toggle(canvas, &canvas -> gx_canvas_dirty_area);
442                     }
443                 }
444             }
445             /* reset the canvas draw counter */
446             canvas -> gx_canvas_draw_count = 0;
447             root = (GX_WINDOW_ROOT *)root -> gx_widget_next;
448         }
449     }
450 
451     /* unlock access to GUIX */
452     GX_EXIT_CRITICAL
453 
454     return status;
455 }
456 
457