mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	
		
			
	
	
		
			92 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			92 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#include <limits.h>
							 | 
						||
| 
								 | 
							
								#include "util/rect_union.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void box_union(pixman_box32_t *dst, pixman_box32_t box) {
							 | 
						||
| 
								 | 
							
									dst->x1 = dst->x1 < box.x1 ? dst->x1 : box.x1;
							 | 
						||
| 
								 | 
							
									dst->y1 = dst->y1 < box.y1 ? dst->y1 : box.y1;
							 | 
						||
| 
								 | 
							
									dst->x2 = dst->x2 > box.x2 ? dst->x2 : box.x2;
							 | 
						||
| 
								 | 
							
									dst->y2 = dst->y2 > box.y2 ? dst->y2 : box.y2;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static bool box_empty_or_invalid(pixman_box32_t box) {
							 | 
						||
| 
								 | 
							
									return box.x1 >= box.x2 || box.y1 >= box.y2;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rect_union_init(struct rect_union *ru) {
							 | 
						||
| 
								 | 
							
									*ru = (struct rect_union) {
							 | 
						||
| 
								 | 
							
										.alloc_failure = false,
							 | 
						||
| 
								 | 
							
										.bounding_box = (pixman_box32_t) {
							 | 
						||
| 
								 | 
							
											.x1 = INT_MAX,
							 | 
						||
| 
								 | 
							
											.x2 = INT_MIN,
							 | 
						||
| 
								 | 
							
											.y1 = INT_MAX,
							 | 
						||
| 
								 | 
							
											.y2 = INT_MIN,
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									pixman_region32_init(&ru->region);
							 | 
						||
| 
								 | 
							
									wl_array_init(&ru->unsorted);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rect_union_finish(struct rect_union *ru) {
							 | 
						||
| 
								 | 
							
									pixman_region32_fini(&ru->region);
							 | 
						||
| 
								 | 
							
									wl_array_release(&ru->unsorted);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void handle_alloc_failure(struct rect_union *ru) {
							 | 
						||
| 
								 | 
							
									ru->alloc_failure = true;
							 | 
						||
| 
								 | 
							
									wl_array_release(&ru->unsorted);
							 | 
						||
| 
								 | 
							
									wl_array_init(&ru->unsorted);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void rect_union_add(struct rect_union *ru, pixman_box32_t box) {
							 | 
						||
| 
								 | 
							
									if (box_empty_or_invalid(box)) {
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									box_union(&ru->bounding_box, box);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!ru->alloc_failure) {
							 | 
						||
| 
								 | 
							
										pixman_box32_t *entry = wl_array_add(&ru->unsorted, sizeof(*entry));
							 | 
						||
| 
								 | 
							
										if (entry) {
							 | 
						||
| 
								 | 
							
											*entry = box;
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											handle_alloc_failure(ru);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const pixman_region32_t *rect_union_evaluate(struct rect_union *ru) {
							 | 
						||
| 
								 | 
							
									if (ru->alloc_failure) {
							 | 
						||
| 
								 | 
							
										goto bounding_box;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int nrects = (int)(ru->unsorted.size / sizeof(pixman_box32_t));
							 | 
						||
| 
								 | 
							
									pixman_region32_t reg;
							 | 
						||
| 
								 | 
							
									bool ok = pixman_region32_init_rects(®, ru->unsorted.data, nrects);
							 | 
						||
| 
								 | 
							
									if (!ok) {
							 | 
						||
| 
								 | 
							
										handle_alloc_failure(ru);
							 | 
						||
| 
								 | 
							
										goto bounding_box;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									ok = pixman_region32_union(®, ®, &ru->region);
							 | 
						||
| 
								 | 
							
									if (!ok) {
							 | 
						||
| 
								 | 
							
										pixman_region32_fini(®);
							 | 
						||
| 
								 | 
							
										handle_alloc_failure(ru);
							 | 
						||
| 
								 | 
							
										goto bounding_box;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									pixman_region32_fini(&ru->region);
							 | 
						||
| 
								 | 
							
									// pixman_region32_t is safe to move
							 | 
						||
| 
								 | 
							
									ru->region = reg;
							 | 
						||
| 
								 | 
							
									wl_array_release(&ru->unsorted);
							 | 
						||
| 
								 | 
							
									wl_array_init(&ru->unsorted);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &ru->region;
							 | 
						||
| 
								 | 
							
								bounding_box:
							 | 
						||
| 
								 | 
							
									pixman_region32_fini(&ru->region);
							 | 
						||
| 
								 | 
							
									if (box_empty_or_invalid(ru->bounding_box)) {
							 | 
						||
| 
								 | 
							
										pixman_region32_init(&ru->region);
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										pixman_region32_init_with_extents(&ru->region, &ru->bounding_box);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return &ru->region;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |