free_region(struct surface_region * reg)1 static void free_region(struct surface_region* reg)
2 {
3 	struct surface_region* last = reg;
4 
5 	while (last){
6 		struct surface_region* next = last->next;
7 		last->next = NULL;
8 		free(last);
9 		last = next;
10 	}
11 }
12 
region_destroy(struct wl_client * client,struct wl_resource * res)13 static void region_destroy(struct wl_client* client, struct wl_resource* res)
14 {
15 	trace(TRACE_REGION, "region_destroy");
16 	free_region(wl_resource_get_user_data(res));
17 }
18 
duplicate_region(struct surface_region * reg)19 static struct surface_region* duplicate_region(struct surface_region* reg)
20 {
21 	struct surface_region* res = malloc(sizeof(struct surface_region));
22 	if (!res)
23 		return NULL;
24 
25 	memcpy(res, reg, sizeof(struct surface_region));
26 
27 	while (reg->next){
28 		res->next = malloc(sizeof(struct surface_region));
29 		if (!res->next)
30 			return res;
31 
32 		memcpy(res->next, reg->next, sizeof(struct surface_region));
33 		reg = reg->next;
34 	}
35 
36 	return res;
37 }
38 
find_free_region_slot(struct surface_region * reg,size_t max_depth)39 static struct region* find_free_region_slot(
40 	struct surface_region* reg, size_t max_depth)
41 {
42 	for (size_t i = 0; i < max_depth; i++){
43 		for (size_t j = 0; j < COUNT_OF(reg->regions); j++){
44 			if (reg->regions[j].op == REGION_OP_IGNORE)
45 				return &reg->regions[j];
46 		}
47 
48 		if (!reg->next && i < max_depth - 1){
49 			struct surface_region* nr = malloc(sizeof(struct surface_region));
50 			*nr = (struct surface_region){0};
51 			reg->next = nr;
52 		}
53 
54 		reg = reg->next;
55 	}
56 
57 	return NULL;
58 }
59 
60 /* protocol unspecified with negative width, negative height - more ambitious
61  * would be the sort/merge/split set of operations to make intersect/union/...
62  * more bearable */
coord_to_reg(struct region * reg,int32_t x,int32_t y,int32_t width,int32_t height)63 static void coord_to_reg(struct region* reg,
64 	int32_t x, int32_t y, int32_t width, int32_t height)
65 {
66 	size_t x1 = x;
67 	size_t y1 = y;
68 	size_t x2 = x + width;
69 	size_t y2 = y + height;
70 
71 	if (width < 0){
72 		x2 = x;
73 		x1 = x + width;
74 	}
75 
76 	if (height < 0){
77 		y2 = y;
78 		y1 = y + height;
79 	}
80 	reg->x1 = x1;
81 	reg->x2 = x2;
82 	reg->y1 = y1;
83 	reg->y2 = y2;
84 }
85 
region_add(struct wl_client * client,struct wl_resource * res,int32_t x,int32_t y,int32_t width,int32_t height)86 static void region_add(struct wl_client* client,
87 	struct wl_resource* res, int32_t x, int32_t y, int32_t width, int32_t height)
88 {
89 	trace(TRACE_REGION,
90 		"region_add(%"PRId32", %"PRId32", +%"PRId32", +%"PRId32")", x, y, width, height);
91 	struct surface_region* reg = wl_resource_get_user_data(res);
92 	struct region* nr = find_free_region_slot(reg, 4);
93 	if (!nr)
94 		return;
95 
96 	coord_to_reg(nr, x, y, width, height);
97 	nr->op = REGION_OP_ADD;
98 }
99 
region_sub(struct wl_client * client,struct wl_resource * res,int32_t x,int32_t y,int32_t width,int32_t height)100 static void region_sub(struct wl_client* client,
101 	struct wl_resource* res, int32_t x, int32_t y, int32_t width, int32_t height)
102 {
103 	trace(TRACE_REGION,
104 		"region_sub(%"PRId32", %"PRId32", +%"PRId32", +%"PRId32")", x, y, width, height);
105 	struct surface_region* reg = wl_resource_get_user_data(res);
106 	struct region* nr = find_free_region_slot(reg, 4);
107 	if (!nr)
108 		return;
109 
110 	coord_to_reg(nr, x, y, width, height);
111 	nr->op = REGION_OP_SUB;
112 }
113