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_utility.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _gx_system_dirty_overlap_check                      PORTABLE C      */
36 /*                                                           6.1          */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Kenneth Maxwell, Microsoft Corporation                              */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function checks if it has overlapping dirty area with others.  */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    dirty                                 Pointer to dirty area         */
48 /*                                                                        */
49 /*  OUTPUT                                                                */
50 /*                                                                        */
51 /*    None                                                                */
52 /*                                                                        */
53 /*  CALLS                                                                 */
54 /*                                                                        */
55 /*    _gx_utility_rectangle_overlap_detect  Detect overlap of rectangles  */
56 /*                                                                        */
57 /*  CALLED BY                                                             */
58 /*                                                                        */
59 /*    _gx_system_dirty_list_trim            Calculate and trim dirty list */
60 /*                                                                        */
61 /*  RELEASE HISTORY                                                       */
62 /*                                                                        */
63 /*    DATE              NAME                      DESCRIPTION             */
64 /*                                                                        */
65 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
66 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
67 /*                                            resulting in version 6.1    */
68 /*                                                                        */
69 /**************************************************************************/
_gx_system_dirty_overlap_check(GX_DIRTY_AREA * dirty)70 static VOID _gx_system_dirty_overlap_check(GX_DIRTY_AREA *dirty)
71 {
72 GX_WIDGET      *dirty_widget;
73 GX_WIDGET      *sibling;
74 GX_WIDGET      *parent;
75 
76     dirty_widget = dirty -> gx_dirty_area_widget;
77     parent = dirty_widget -> gx_widget_parent;
78 
79     while (parent)
80     {
81         /* check to see if this is a viewport owner */
82         if (dirty -> gx_dirty_area_widget -> gx_widget_type >= GX_TYPE_WINDOW)
83         {
84             if (parent -> gx_widget_type == GX_TYPE_ROOT_WINDOW)
85             {
86                 /* this widget is a view owner, no need to go further */
87                 return;
88             }
89         }
90 
91         /* not a view owner, so check to see if it has overlapping siblings */
92         sibling = dirty_widget -> gx_widget_next;
93 
94         while(sibling)
95         {
96             if (_gx_utility_rectangle_overlap_detect(&sibling -> gx_widget_size, &dirty -> gx_dirty_area_rectangle, NULL))
97             {
98                 /* mark the parent as dirty, so that both children are drawn */
99                 dirty_widget = parent;
100                 dirty -> gx_dirty_area_widget = dirty_widget;
101                 break;
102             }
103             sibling = sibling->gx_widget_next;
104         }
105         dirty_widget = parent;
106         parent = dirty_widget -> gx_widget_parent;
107     }
108 }
109 
110 /**************************************************************************/
111 /*                                                                        */
112 /*  FUNCTION                                               RELEASE        */
113 /*                                                                        */
114 /*    _gx_system_dirty_list_trim                          PORTABLE C      */
115 /*                                                           6.1          */
116 /*  AUTHOR                                                                */
117 /*                                                                        */
118 /*    Kenneth Maxwell, Microsoft Corporation                              */
119 /*                                                                        */
120 /*  DESCRIPTION                                                           */
121 /*                                                                        */
122 /*    This function trims the dirty list to reduce redundancy and         */
123 /*    eliminate invalid entries prior to refreshing the canvas. This      */
124 /*    function returns the sum of the remaining dirty areas               */
125 /*                                                                        */
126 /*  INPUT                                                                 */
127 /*                                                                        */
128 /*    dirty_area                            Pointer to return value       */
129 /*    root                                  Point to the root window      */
130 /*                                                                        */
131 /*  OUTPUT                                                                */
132 /*                                                                        */
133 /*    [GX_TRUE | GX_FALSE]                  GX_TRUE if dirty, otherwise   */
134 /*                                            GX_FALSE                    */
135 /*                                                                        */
136 /*  CALLS                                                                 */
137 /*                                                                        */
138 /*    _gx_utility_rectangle_combine         Combine two rectangles        */
139 /*    _gx_utility_rectangle_define          Define a rectangle            */
140 /*    _gx_utility_rectangle_overlap_detect  Detect overlap of rectangles  */
141 /*    _gx_system_dirty_overlap_check        Detect overlapping children   */
142 /*                                                                        */
143 /*  CALLED BY                                                             */
144 /*                                                                        */
145 /*    _gx_system_canvas_refresh             Refresh the canvas            */
146 /*                                                                        */
147 /*  RELEASE HISTORY                                                       */
148 /*                                                                        */
149 /*    DATE              NAME                      DESCRIPTION             */
150 /*                                                                        */
151 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
152 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
153 /*                                            resulting in version 6.1    */
154 /*                                                                        */
155 /**************************************************************************/
_gx_system_dirty_list_trim(GX_RECTANGLE * dirty_area,GX_WINDOW_ROOT * root)156 UINT  _gx_system_dirty_list_trim(GX_RECTANGLE *dirty_area, GX_WINDOW_ROOT *root)
157 {
158 
159 UINT           index_1;
160 UINT           index_2;
161 GX_DIRTY_AREA *dirty;
162 GX_DIRTY_AREA *dirty2;
163 GX_CANVAS     *canvas;
164 GX_WIDGET     *parent;
165 
166     /* pick up pointer to canvas */
167     canvas = root -> gx_window_root_canvas;
168 
169     /* Initialize a dirty area rectangle.  */
170     _gx_utility_rectangle_define(dirty_area, canvas -> gx_canvas_x_resolution,
171                                  canvas -> gx_canvas_y_resolution, -1, -1);
172 
173     /* Setup pointer to start of dirty area list.  */
174     dirty =  canvas -> gx_canvas_dirty_list;
175 
176     /* This loop looks for invalid entries (invisible) and
177        entries that have overlappers in the z order, in
178        which case we need to back up the drawing layer
179      */
180 
181     for (index_1 = 0; index_1 < canvas -> gx_canvas_dirty_count; index_1++)
182     {
183         /* Is there a widget for this dirty area entry?  */
184         if (dirty -> gx_dirty_area_widget == GX_NULL)
185         {
186             dirty++;
187             continue;
188         }
189 
190         if (!(dirty -> gx_dirty_area_widget -> gx_widget_status & GX_STATUS_VISIBLE))
191         {
192             dirty -> gx_dirty_area_widget = GX_NULL;
193             dirty++;
194             continue;
195         }
196 
197         /* check to see if we need to modify the drawing level because of overlapping
198            siblings
199         */
200          _gx_system_dirty_overlap_check(dirty);
201         dirty++;
202     }
203 
204     /* This loop tests to see if a dirty entry also has a parent
205        that is marked as dirty. If the dirty rectangles overlap,
206        just combine the rectangles and get rid of the child entry
207      */
208 
209     dirty =  canvas -> gx_canvas_dirty_list;
210 
211     for (index_1 = 0; index_1 < canvas -> gx_canvas_dirty_count; index_1++)
212     {
213         /* Is there a widget for this dirty area entry?  */
214         if (dirty -> gx_dirty_area_widget == GX_NULL)
215         {
216             dirty++;
217             continue;
218         }
219 
220         /* Yes, there is a widget. Loop through the dirty area array.  */
221         for (index_2 = 0; index_2 < canvas -> gx_canvas_dirty_count; index_2++)
222         {
223             /* Pickup the next dirty area entry.  */
224             dirty2 = &canvas -> gx_canvas_dirty_list[index_2];
225 
226             /* Is is valid?  */
227             if ((dirty2 -> gx_dirty_area_widget) && (dirty != dirty2))
228             {
229                 parent = dirty2 -> gx_dirty_area_widget -> gx_widget_parent;
230 
231                 while (parent && (parent != dirty -> gx_dirty_area_widget))
232                 {
233                     parent = parent -> gx_widget_parent;
234                 }
235 
236                 /* check to see if one is parent of the other */
237                 if (parent == dirty -> gx_dirty_area_widget)
238                 {
239                     /* dirty1 is parent of dirty2, do the dirty
240                         rectangles overlap?  */
241                     if (_gx_utility_rectangle_overlap_detect(&dirty -> gx_dirty_area_rectangle, &dirty2 -> gx_dirty_area_rectangle, NULL))
242                     {
243                         /* Yes, combine the two entries into one and NULL out the child entry.  */
244                         _gx_utility_rectangle_combine(&dirty -> gx_dirty_area_rectangle, &dirty2 -> gx_dirty_area_rectangle);
245 
246                         /* NULL out the child entry.  */
247                         dirty2 -> gx_dirty_area_widget = GX_NULL;
248                         continue;
249                     }
250                 }
251 
252                 /* check to see if two entries for same widget */
253                 if (dirty2 -> gx_dirty_area_widget == dirty -> gx_dirty_area_widget)
254                 {
255                     /* same widget marked twice */
256                     /* do the dirty rectangles overlap?  */
257                     if (_gx_utility_rectangle_overlap_detect(&dirty -> gx_dirty_area_rectangle, &dirty2 -> gx_dirty_area_rectangle, NULL))
258                     {
259                         /* Yes, combine the two entries into one and NULL out the child entry.  */
260                         _gx_utility_rectangle_combine(&dirty -> gx_dirty_area_rectangle, &dirty2 -> gx_dirty_area_rectangle);
261 
262                         /* NULL out the second entry.  */
263                         dirty2 -> gx_dirty_area_widget =  GX_NULL;
264                     }
265                 }
266             }
267         }
268 
269         /* Add to our overall sum of dirty area.  */
270         _gx_utility_rectangle_combine(dirty_area, &(dirty -> gx_dirty_area_rectangle));
271 
272         /* Move to next dirty area entry.  */
273         dirty++;
274     }
275 
276     /* Do we have anything to draw?  */
277     if ((dirty_area -> gx_rectangle_left <= dirty_area -> gx_rectangle_right) &&
278         (dirty_area -> gx_rectangle_top <= dirty_area -> gx_rectangle_bottom))
279     {
280 
281         /* Yes, we have something to draw.  */
282         return(GX_TRUE);
283     }
284     else
285     {
286 
287         /* No, nothing left after trimming duplicates.  */
288         return(GX_FALSE);
289     }
290 }
291 
292