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