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