1 #include <assert.h>
2 #include <stdlib.h>
3 #include <wayland-server-core.h>
4 #include <wlr/render/interface.h>
5 #include <wlr/types/wlr_buffer.h>
6 #include <wlr/types/wlr_compositor.h>
7 #include <wlr/types/wlr_matrix.h>
8 #include <wlr/types/wlr_region.h>
9 #include <wlr/types/wlr_surface.h>
10 #include <wlr/types/wlr_output.h>
11 #include <wlr/util/log.h>
12 #include <wlr/util/region.h>
13 #include "util/signal.h"
14 #include "util/time.h"
15 
16 #define CALLBACK_VERSION 1
17 #define SURFACE_VERSION 4
18 #define SUBSURFACE_VERSION 1
19 
min(int fst,int snd)20 static int min(int fst, int snd) {
21 	if (fst < snd) {
22 		return fst;
23 	} else {
24 		return snd;
25 	}
26 }
27 
max(int fst,int snd)28 static int max(int fst, int snd) {
29 	if (fst > snd) {
30 		return fst;
31 	} else {
32 		return snd;
33 	}
34 }
35 
surface_state_reset_buffer(struct wlr_surface_state * state)36 static void surface_state_reset_buffer(struct wlr_surface_state *state) {
37 	if (state->buffer_resource) {
38 		wl_list_remove(&state->buffer_destroy.link);
39 		state->buffer_resource = NULL;
40 	}
41 }
42 
surface_handle_buffer_destroy(struct wl_listener * listener,void * data)43 static void surface_handle_buffer_destroy(struct wl_listener *listener,
44 		void *data) {
45 	struct wlr_surface_state *state =
46 		wl_container_of(listener, state, buffer_destroy);
47 	surface_state_reset_buffer(state);
48 }
49 
surface_state_set_buffer(struct wlr_surface_state * state,struct wl_resource * buffer_resource)50 static void surface_state_set_buffer(struct wlr_surface_state *state,
51 		struct wl_resource *buffer_resource) {
52 	surface_state_reset_buffer(state);
53 
54 	state->buffer_resource = buffer_resource;
55 	if (buffer_resource != NULL) {
56 		wl_resource_add_destroy_listener(buffer_resource,
57 			&state->buffer_destroy);
58 		state->buffer_destroy.notify = surface_handle_buffer_destroy;
59 	}
60 }
61 
surface_destroy(struct wl_client * client,struct wl_resource * resource)62 static void surface_destroy(struct wl_client *client,
63 		struct wl_resource *resource) {
64 	wl_resource_destroy(resource);
65 }
66 
surface_attach(struct wl_client * client,struct wl_resource * resource,struct wl_resource * buffer,int32_t dx,int32_t dy)67 static void surface_attach(struct wl_client *client,
68 		struct wl_resource *resource,
69 		struct wl_resource *buffer, int32_t dx, int32_t dy) {
70 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
71 
72 	surface->pending.committed |= WLR_SURFACE_STATE_BUFFER;
73 	surface->pending.dx = dx;
74 	surface->pending.dy = dy;
75 	surface_state_set_buffer(&surface->pending, buffer);
76 }
77 
surface_damage(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)78 static void surface_damage(struct wl_client *client,
79 		struct wl_resource *resource,
80 		int32_t x, int32_t y, int32_t width, int32_t height) {
81 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
82 	if (width < 0 || height < 0) {
83 		return;
84 	}
85 	surface->pending.committed |= WLR_SURFACE_STATE_SURFACE_DAMAGE;
86 	pixman_region32_union_rect(&surface->pending.surface_damage,
87 		&surface->pending.surface_damage,
88 		x, y, width, height);
89 }
90 
callback_handle_resource_destroy(struct wl_resource * resource)91 static void callback_handle_resource_destroy(struct wl_resource *resource) {
92 	wl_list_remove(wl_resource_get_link(resource));
93 }
94 
surface_frame(struct wl_client * client,struct wl_resource * resource,uint32_t callback)95 static void surface_frame(struct wl_client *client,
96 		struct wl_resource *resource, uint32_t callback) {
97 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
98 
99 	struct wl_resource *callback_resource = wl_resource_create(client,
100 		&wl_callback_interface, CALLBACK_VERSION, callback);
101 	if (callback_resource == NULL) {
102 		wl_resource_post_no_memory(resource);
103 		return;
104 	}
105 	wl_resource_set_implementation(callback_resource, NULL, NULL,
106 		callback_handle_resource_destroy);
107 
108 	wl_list_insert(surface->pending.frame_callback_list.prev,
109 		wl_resource_get_link(callback_resource));
110 
111 	surface->pending.committed |= WLR_SURFACE_STATE_FRAME_CALLBACK_LIST;
112 }
113 
surface_set_opaque_region(struct wl_client * client,struct wl_resource * resource,struct wl_resource * region_resource)114 static void surface_set_opaque_region(struct wl_client *client,
115 		struct wl_resource *resource,
116 		struct wl_resource *region_resource) {
117 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
118 	surface->pending.committed |= WLR_SURFACE_STATE_OPAQUE_REGION;
119 	if (region_resource) {
120 		pixman_region32_t *region = wlr_region_from_resource(region_resource);
121 		pixman_region32_copy(&surface->pending.opaque, region);
122 	} else {
123 		pixman_region32_clear(&surface->pending.opaque);
124 	}
125 }
126 
surface_set_input_region(struct wl_client * client,struct wl_resource * resource,struct wl_resource * region_resource)127 static void surface_set_input_region(struct wl_client *client,
128 		struct wl_resource *resource,
129 		struct wl_resource *region_resource) {
130 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
131 	surface->pending.committed |= WLR_SURFACE_STATE_INPUT_REGION;
132 	if (region_resource) {
133 		pixman_region32_t *region = wlr_region_from_resource(region_resource);
134 		pixman_region32_copy(&surface->pending.input, region);
135 	} else {
136 		pixman_region32_fini(&surface->pending.input);
137 		pixman_region32_init_rect(&surface->pending.input,
138 			INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
139 	}
140 }
141 
142 /**
143  * Computes the surface viewport source size, ie. the size after applying the
144  * surface's scale, transform and cropping (via the viewport's source
145  * rectangle) but before applying the viewport scaling (via the viewport's
146  * destination rectangle).
147  */
surface_state_viewport_src_size(struct wlr_surface_state * state,int * out_width,int * out_height)148 static void surface_state_viewport_src_size(struct wlr_surface_state *state,
149 		int *out_width, int *out_height) {
150 	if (state->buffer_width == 0 && state->buffer_height == 0) {
151 		*out_width = *out_height = 0;
152 		return;
153 	}
154 
155 	if (state->viewport.has_src) {
156 		*out_width = state->viewport.src.width;
157 		*out_height = state->viewport.src.height;
158 	} else {
159 		int width = state->buffer_width / state->scale;
160 		int height = state->buffer_height / state->scale;
161 		if ((state->transform & WL_OUTPUT_TRANSFORM_90) != 0) {
162 			int tmp = width;
163 			width = height;
164 			height = tmp;
165 		}
166 		*out_width = width;
167 		*out_height = height;
168 	}
169 }
170 
surface_state_finalize(struct wlr_surface * surface,struct wlr_surface_state * state)171 static void surface_state_finalize(struct wlr_surface *surface,
172 		struct wlr_surface_state *state) {
173 	if ((state->committed & WLR_SURFACE_STATE_BUFFER)) {
174 		if (state->buffer_resource != NULL) {
175 			wlr_resource_get_buffer_size(state->buffer_resource,
176 				surface->renderer, &state->buffer_width, &state->buffer_height);
177 		} else {
178 			state->buffer_width = state->buffer_height = 0;
179 		}
180 	}
181 
182 	if (state->viewport.has_dst) {
183 		if (state->buffer_width == 0 && state->buffer_height == 0) {
184 			state->width = state->height = 0;
185 		} else {
186 			state->width = state->viewport.dst_width;
187 			state->height = state->viewport.dst_height;
188 		}
189 	} else {
190 		surface_state_viewport_src_size(state,
191 			&state->width, &state->height);
192 	}
193 
194 	pixman_region32_intersect_rect(&state->surface_damage,
195 		&state->surface_damage, 0, 0, state->width, state->height);
196 
197 	pixman_region32_intersect_rect(&state->buffer_damage,
198 		&state->buffer_damage, 0, 0, state->buffer_width,
199 		state->buffer_height);
200 }
201 
surface_update_damage(pixman_region32_t * buffer_damage,struct wlr_surface_state * current,struct wlr_surface_state * pending)202 static void surface_update_damage(pixman_region32_t *buffer_damage,
203 		struct wlr_surface_state *current, struct wlr_surface_state *pending) {
204 	pixman_region32_clear(buffer_damage);
205 
206 	if (pending->width != current->width ||
207 			pending->height != current->height) {
208 		// Damage the whole buffer on resize
209 		pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0,
210 			pending->buffer_width, pending->buffer_height);
211 	} else {
212 		// Copy over surface damage + buffer damage
213 		pixman_region32_t surface_damage;
214 		pixman_region32_init(&surface_damage);
215 
216 		pixman_region32_copy(&surface_damage, &pending->surface_damage);
217 
218 		if (pending->viewport.has_dst) {
219 			int src_width, src_height;
220 			surface_state_viewport_src_size(pending, &src_width, &src_height);
221 			float scale_x = (float)pending->viewport.dst_width / src_width;
222 			float scale_y = (float)pending->viewport.dst_height / src_height;
223 			wlr_region_scale_xy(&surface_damage, &surface_damage,
224 				1.0 / scale_x, 1.0 / scale_y);
225 		}
226 		if (pending->viewport.has_src) {
227 			// This is lossy: do a best-effort conversion
228 			pixman_region32_translate(&surface_damage,
229 				floor(pending->viewport.src.x),
230 				floor(pending->viewport.src.y));
231 		}
232 
233 		wlr_region_transform(&surface_damage, &surface_damage,
234 			wlr_output_transform_invert(pending->transform),
235 			pending->width, pending->height);
236 		wlr_region_scale(&surface_damage, &surface_damage, pending->scale);
237 
238 		pixman_region32_union(buffer_damage,
239 			&pending->buffer_damage, &surface_damage);
240 
241 		pixman_region32_fini(&surface_damage);
242 	}
243 }
244 
surface_state_copy(struct wlr_surface_state * state,struct wlr_surface_state * next)245 static void surface_state_copy(struct wlr_surface_state *state,
246 		struct wlr_surface_state *next) {
247 	state->width = next->width;
248 	state->height = next->height;
249 	state->buffer_width = next->buffer_width;
250 	state->buffer_height = next->buffer_height;
251 
252 	if (next->committed & WLR_SURFACE_STATE_SCALE) {
253 		state->scale = next->scale;
254 	}
255 	if (next->committed & WLR_SURFACE_STATE_TRANSFORM) {
256 		state->transform = next->transform;
257 	}
258 	if (next->committed & WLR_SURFACE_STATE_BUFFER) {
259 		state->dx = next->dx;
260 		state->dy = next->dy;
261 	} else {
262 		state->dx = state->dy = 0;
263 	}
264 	if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) {
265 		pixman_region32_copy(&state->surface_damage, &next->surface_damage);
266 	} else {
267 		pixman_region32_clear(&state->surface_damage);
268 	}
269 	if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) {
270 		pixman_region32_copy(&state->buffer_damage, &next->buffer_damage);
271 	} else {
272 		pixman_region32_clear(&state->buffer_damage);
273 	}
274 	if (next->committed & WLR_SURFACE_STATE_OPAQUE_REGION) {
275 		pixman_region32_copy(&state->opaque, &next->opaque);
276 	}
277 	if (next->committed & WLR_SURFACE_STATE_INPUT_REGION) {
278 		pixman_region32_copy(&state->input, &next->input);
279 	}
280 	if (next->committed & WLR_SURFACE_STATE_VIEWPORT) {
281 		memcpy(&state->viewport, &next->viewport, sizeof(state->viewport));
282 	}
283 
284 	state->committed |= next->committed;
285 }
286 
287 /**
288  * Append pending state to current state and clear pending state.
289  */
surface_state_move(struct wlr_surface_state * state,struct wlr_surface_state * next)290 static void surface_state_move(struct wlr_surface_state *state,
291 		struct wlr_surface_state *next) {
292 	surface_state_copy(state, next);
293 
294 	if (next->committed & WLR_SURFACE_STATE_BUFFER) {
295 		surface_state_set_buffer(state, next->buffer_resource);
296 		surface_state_reset_buffer(next);
297 		next->dx = next->dy = 0;
298 	}
299 	if (next->committed & WLR_SURFACE_STATE_SURFACE_DAMAGE) {
300 		pixman_region32_clear(&next->surface_damage);
301 	}
302 	if (next->committed & WLR_SURFACE_STATE_BUFFER_DAMAGE) {
303 		pixman_region32_clear(&next->buffer_damage);
304 	}
305 	if (next->committed & WLR_SURFACE_STATE_FRAME_CALLBACK_LIST) {
306 		wl_list_insert_list(&state->frame_callback_list,
307 			&next->frame_callback_list);
308 		wl_list_init(&next->frame_callback_list);
309 	}
310 
311 	next->committed = 0;
312 }
313 
surface_damage_subsurfaces(struct wlr_subsurface * subsurface)314 static void surface_damage_subsurfaces(struct wlr_subsurface *subsurface) {
315 	// XXX: This is probably the wrong way to do it, because this damage should
316 	// come from the client, but weston doesn't do it correctly either and it
317 	// seems to work ok. See the comment on weston_surface_damage for more info
318 	// about a better approach.
319 	struct wlr_surface *surface = subsurface->surface;
320 	pixman_region32_union_rect(&surface->buffer_damage,
321 		&surface->buffer_damage, 0, 0,
322 		surface->current.buffer_width, surface->current.buffer_height);
323 
324 	subsurface->reordered = false;
325 
326 	struct wlr_subsurface *child;
327 	wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
328 		surface_damage_subsurfaces(child);
329 	}
330 }
331 
surface_apply_damage(struct wlr_surface * surface)332 static void surface_apply_damage(struct wlr_surface *surface) {
333 	struct wl_resource *resource = surface->current.buffer_resource;
334 	if (resource == NULL) {
335 		// NULL commit
336 		if (surface->buffer != NULL) {
337 			wlr_buffer_unlock(&surface->buffer->base);
338 		}
339 		surface->buffer = NULL;
340 		return;
341 	}
342 
343 	if (surface->buffer != NULL && surface->buffer->resource_released) {
344 		struct wlr_client_buffer *updated_buffer =
345 			wlr_client_buffer_apply_damage(surface->buffer, resource,
346 			&surface->buffer_damage);
347 		if (updated_buffer != NULL) {
348 			surface->buffer = updated_buffer;
349 			return;
350 		}
351 	}
352 
353 	struct wlr_client_buffer *buffer =
354 		wlr_client_buffer_import(surface->renderer, resource);
355 	if (buffer == NULL) {
356 		wlr_log(WLR_ERROR, "Failed to upload buffer");
357 		return;
358 	}
359 
360 	if (surface->buffer != NULL) {
361 		wlr_buffer_unlock(&surface->buffer->base);
362 	}
363 	surface->buffer = buffer;
364 }
365 
surface_update_opaque_region(struct wlr_surface * surface)366 static void surface_update_opaque_region(struct wlr_surface *surface) {
367 	struct wlr_texture *texture = wlr_surface_get_texture(surface);
368 	if (texture == NULL) {
369 		pixman_region32_clear(&surface->opaque_region);
370 		return;
371 	}
372 
373 	if (wlr_texture_is_opaque(texture)) {
374 		pixman_region32_init_rect(&surface->opaque_region,
375 			0, 0, surface->current.width, surface->current.height);
376 		return;
377 	}
378 
379 	pixman_region32_intersect_rect(&surface->opaque_region,
380 		&surface->current.opaque,
381 		0, 0, surface->current.width, surface->current.height);
382 }
383 
surface_update_input_region(struct wlr_surface * surface)384 static void surface_update_input_region(struct wlr_surface *surface) {
385 	pixman_region32_intersect_rect(&surface->input_region,
386 		&surface->current.input,
387 		0, 0, surface->current.width, surface->current.height);
388 }
389 
surface_commit_pending(struct wlr_surface * surface)390 static void surface_commit_pending(struct wlr_surface *surface) {
391 	surface_state_finalize(surface, &surface->pending);
392 
393 	if (surface->role && surface->role->precommit) {
394 		surface->role->precommit(surface);
395 	}
396 
397 	bool invalid_buffer = surface->pending.committed & WLR_SURFACE_STATE_BUFFER;
398 
399 	surface->sx += surface->pending.dx;
400 	surface->sy += surface->pending.dy;
401 	surface_update_damage(&surface->buffer_damage,
402 		&surface->current, &surface->pending);
403 
404 	surface_state_copy(&surface->previous, &surface->current);
405 	surface_state_move(&surface->current, &surface->pending);
406 
407 	if (invalid_buffer) {
408 		surface_apply_damage(surface);
409 	}
410 	surface_update_opaque_region(surface);
411 	surface_update_input_region(surface);
412 
413 	// commit subsurface order
414 	struct wlr_subsurface *subsurface;
415 	wl_list_for_each_reverse(subsurface, &surface->subsurface_pending_list,
416 			parent_pending_link) {
417 		wl_list_remove(&subsurface->parent_link);
418 		wl_list_insert(&surface->subsurfaces, &subsurface->parent_link);
419 
420 		if (subsurface->reordered) {
421 			// TODO: damage all the subsurfaces
422 			surface_damage_subsurfaces(subsurface);
423 		}
424 	}
425 
426 	if (surface->role && surface->role->commit) {
427 		surface->role->commit(surface);
428 	}
429 
430 	wlr_signal_emit_safe(&surface->events.commit, surface);
431 }
432 
subsurface_is_synchronized(struct wlr_subsurface * subsurface)433 static bool subsurface_is_synchronized(struct wlr_subsurface *subsurface) {
434 	while (subsurface != NULL) {
435 		if (subsurface->synchronized) {
436 			return true;
437 		}
438 
439 		if (!subsurface->parent) {
440 			return false;
441 		}
442 
443 		if (!wlr_surface_is_subsurface(subsurface->parent)) {
444 			break;
445 		}
446 		subsurface = wlr_subsurface_from_wlr_surface(subsurface->parent);
447 	}
448 
449 	return false;
450 }
451 
452 /**
453  * Recursive function to commit the effectively synchronized children.
454  */
subsurface_parent_commit(struct wlr_subsurface * subsurface,bool synchronized)455 static void subsurface_parent_commit(struct wlr_subsurface *subsurface,
456 		bool synchronized) {
457 	struct wlr_surface *surface = subsurface->surface;
458 	if (synchronized || subsurface->synchronized) {
459 		if (subsurface->has_cache) {
460 			surface_state_move(&surface->pending, &subsurface->cached);
461 			surface_commit_pending(surface);
462 			subsurface->has_cache = false;
463 			subsurface->cached.committed = 0;
464 		}
465 
466 		struct wlr_subsurface *subsurface;
467 		wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
468 			subsurface_parent_commit(subsurface, true);
469 		}
470 	}
471 }
472 
subsurface_commit(struct wlr_subsurface * subsurface)473 static void subsurface_commit(struct wlr_subsurface *subsurface) {
474 	struct wlr_surface *surface = subsurface->surface;
475 
476 	if (subsurface_is_synchronized(subsurface)) {
477 		surface_state_move(&subsurface->cached, &surface->pending);
478 		subsurface->has_cache = true;
479 	} else {
480 		if (subsurface->has_cache) {
481 			surface_state_move(&surface->pending, &subsurface->cached);
482 			surface_commit_pending(surface);
483 			subsurface->has_cache = false;
484 		} else {
485 			surface_commit_pending(surface);
486 		}
487 	}
488 }
489 
surface_commit(struct wl_client * client,struct wl_resource * resource)490 static void surface_commit(struct wl_client *client,
491 		struct wl_resource *resource) {
492 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
493 
494 	struct wlr_subsurface *subsurface = wlr_surface_is_subsurface(surface) ?
495 		wlr_subsurface_from_wlr_surface(surface) : NULL;
496 	if (subsurface != NULL) {
497 		subsurface_commit(subsurface);
498 	} else {
499 		surface_commit_pending(surface);
500 	}
501 
502 	wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
503 		subsurface_parent_commit(subsurface, false);
504 	}
505 }
506 
surface_set_buffer_transform(struct wl_client * client,struct wl_resource * resource,int32_t transform)507 static void surface_set_buffer_transform(struct wl_client *client,
508 		struct wl_resource *resource, int32_t transform) {
509 	if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
510 			transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
511 		wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM,
512 			"Specified transform value (%d) is invalid", transform);
513 		return;
514 	}
515 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
516 	surface->pending.committed |= WLR_SURFACE_STATE_TRANSFORM;
517 	surface->pending.transform = transform;
518 }
519 
surface_set_buffer_scale(struct wl_client * client,struct wl_resource * resource,int32_t scale)520 static void surface_set_buffer_scale(struct wl_client *client,
521 		struct wl_resource *resource, int32_t scale) {
522 	if (scale <= 0) {
523 		wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE,
524 			"Specified scale value (%d) is not positive", scale);
525 		return;
526 	}
527 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
528 	surface->pending.committed |= WLR_SURFACE_STATE_SCALE;
529 	surface->pending.scale = scale;
530 }
531 
surface_damage_buffer(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)532 static void surface_damage_buffer(struct wl_client *client,
533 		struct wl_resource *resource,
534 		int32_t x, int32_t y, int32_t width,
535 		int32_t height) {
536 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
537 	if (width < 0 || height < 0) {
538 		return;
539 	}
540 	surface->pending.committed |= WLR_SURFACE_STATE_BUFFER_DAMAGE;
541 	pixman_region32_union_rect(&surface->pending.buffer_damage,
542 		&surface->pending.buffer_damage,
543 		x, y, width, height);
544 }
545 
546 static const struct wl_surface_interface surface_interface = {
547 	.destroy = surface_destroy,
548 	.attach = surface_attach,
549 	.damage = surface_damage,
550 	.frame = surface_frame,
551 	.set_opaque_region = surface_set_opaque_region,
552 	.set_input_region = surface_set_input_region,
553 	.commit = surface_commit,
554 	.set_buffer_transform = surface_set_buffer_transform,
555 	.set_buffer_scale = surface_set_buffer_scale,
556 	.damage_buffer = surface_damage_buffer
557 };
558 
wlr_surface_from_resource(struct wl_resource * resource)559 struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
560 	assert(wl_resource_instance_of(resource, &wl_surface_interface,
561 		&surface_interface));
562 	return wl_resource_get_user_data(resource);
563 }
564 
surface_state_init(struct wlr_surface_state * state)565 static void surface_state_init(struct wlr_surface_state *state) {
566 	state->scale = 1;
567 	state->transform = WL_OUTPUT_TRANSFORM_NORMAL;
568 
569 	wl_list_init(&state->frame_callback_list);
570 
571 	pixman_region32_init(&state->surface_damage);
572 	pixman_region32_init(&state->buffer_damage);
573 	pixman_region32_init(&state->opaque);
574 	pixman_region32_init_rect(&state->input,
575 		INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
576 }
577 
surface_state_finish(struct wlr_surface_state * state)578 static void surface_state_finish(struct wlr_surface_state *state) {
579 	surface_state_reset_buffer(state);
580 
581 	struct wl_resource *resource, *tmp;
582 	wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) {
583 		wl_resource_destroy(resource);
584 	}
585 
586 	pixman_region32_fini(&state->surface_damage);
587 	pixman_region32_fini(&state->buffer_damage);
588 	pixman_region32_fini(&state->opaque);
589 	pixman_region32_fini(&state->input);
590 }
591 
592 static void subsurface_unmap(struct wlr_subsurface *subsurface);
593 
subsurface_destroy(struct wlr_subsurface * subsurface)594 static void subsurface_destroy(struct wlr_subsurface *subsurface) {
595 	if (subsurface == NULL) {
596 		return;
597 	}
598 
599 	subsurface_unmap(subsurface);
600 
601 	wlr_signal_emit_safe(&subsurface->events.destroy, subsurface);
602 
603 	wl_list_remove(&subsurface->surface_destroy.link);
604 	surface_state_finish(&subsurface->cached);
605 
606 	if (subsurface->parent) {
607 		wl_list_remove(&subsurface->parent_link);
608 		wl_list_remove(&subsurface->parent_pending_link);
609 		wl_list_remove(&subsurface->parent_destroy.link);
610 	}
611 
612 	wl_resource_set_user_data(subsurface->resource, NULL);
613 	if (subsurface->surface) {
614 		subsurface->surface->role_data = NULL;
615 	}
616 	free(subsurface);
617 }
618 
surface_handle_resource_destroy(struct wl_resource * resource)619 static void surface_handle_resource_destroy(struct wl_resource *resource) {
620 	struct wlr_surface *surface = wlr_surface_from_resource(resource);
621 
622 	wlr_signal_emit_safe(&surface->events.destroy, surface);
623 
624 	wl_list_remove(wl_resource_get_link(surface->resource));
625 
626 	wl_list_remove(&surface->renderer_destroy.link);
627 	surface_state_finish(&surface->pending);
628 	surface_state_finish(&surface->current);
629 	surface_state_finish(&surface->previous);
630 	pixman_region32_fini(&surface->buffer_damage);
631 	pixman_region32_fini(&surface->opaque_region);
632 	pixman_region32_fini(&surface->input_region);
633 	if (surface->buffer != NULL) {
634 		wlr_buffer_unlock(&surface->buffer->base);
635 	}
636 	free(surface);
637 }
638 
surface_handle_renderer_destroy(struct wl_listener * listener,void * data)639 static void surface_handle_renderer_destroy(struct wl_listener *listener,
640 		void *data) {
641 	struct wlr_surface *surface =
642 		wl_container_of(listener, surface, renderer_destroy);
643 	wl_resource_destroy(surface->resource);
644 }
645 
wlr_surface_create(struct wl_client * client,uint32_t version,uint32_t id,struct wlr_renderer * renderer,struct wl_list * resource_list)646 struct wlr_surface *wlr_surface_create(struct wl_client *client,
647 		uint32_t version, uint32_t id, struct wlr_renderer *renderer,
648 		struct wl_list *resource_list) {
649 	assert(version <= SURFACE_VERSION);
650 
651 	struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
652 	if (!surface) {
653 		wl_client_post_no_memory(client);
654 		return NULL;
655 	}
656 	surface->resource = wl_resource_create(client, &wl_surface_interface,
657 		version, id);
658 	if (surface->resource == NULL) {
659 		free(surface);
660 		wl_client_post_no_memory(client);
661 		return NULL;
662 	}
663 	wl_resource_set_implementation(surface->resource, &surface_interface,
664 		surface, surface_handle_resource_destroy);
665 
666 	wlr_log(WLR_DEBUG, "New wlr_surface %p (res %p)", surface, surface->resource);
667 
668 	surface->renderer = renderer;
669 
670 	surface_state_init(&surface->current);
671 	surface_state_init(&surface->pending);
672 	surface_state_init(&surface->previous);
673 
674 	wl_signal_init(&surface->events.commit);
675 	wl_signal_init(&surface->events.destroy);
676 	wl_signal_init(&surface->events.new_subsurface);
677 	wl_list_init(&surface->subsurfaces);
678 	wl_list_init(&surface->subsurface_pending_list);
679 	pixman_region32_init(&surface->buffer_damage);
680 	pixman_region32_init(&surface->opaque_region);
681 	pixman_region32_init(&surface->input_region);
682 
683 	wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy);
684 	surface->renderer_destroy.notify = surface_handle_renderer_destroy;
685 
686 	struct wl_list *resource_link = wl_resource_get_link(surface->resource);
687 	if (resource_list != NULL) {
688 		wl_list_insert(resource_list, resource_link);
689 	} else {
690 		wl_list_init(resource_link);
691 	}
692 
693 	return surface;
694 }
695 
wlr_surface_get_texture(struct wlr_surface * surface)696 struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) {
697 	if (surface->buffer == NULL) {
698 		return NULL;
699 	}
700 	return surface->buffer->texture;
701 }
702 
wlr_surface_has_buffer(struct wlr_surface * surface)703 bool wlr_surface_has_buffer(struct wlr_surface *surface) {
704 	return wlr_surface_get_texture(surface) != NULL;
705 }
706 
wlr_surface_set_role(struct wlr_surface * surface,const struct wlr_surface_role * role,void * role_data,struct wl_resource * error_resource,uint32_t error_code)707 bool wlr_surface_set_role(struct wlr_surface *surface,
708 		const struct wlr_surface_role *role, void *role_data,
709 		struct wl_resource *error_resource, uint32_t error_code) {
710 	assert(role != NULL);
711 
712 	if (surface->role != NULL && surface->role != role) {
713 		if (error_resource != NULL) {
714 			wl_resource_post_error(error_resource, error_code,
715 				"Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n",
716 				role->name, wl_resource_get_id(surface->resource),
717 				surface->role->name);
718 		}
719 		return false;
720 	}
721 	if (surface->role_data != NULL && surface->role_data != role_data) {
722 		wl_resource_post_error(error_resource, error_code,
723 			"Cannot reassign role %s to wl_surface@%" PRIu32 ","
724 			"role object still exists", role->name,
725 			wl_resource_get_id(surface->resource));
726 		return false;
727 	}
728 
729 	surface->role = role;
730 	surface->role_data = role_data;
731 	return true;
732 }
733 
734 static const struct wl_subsurface_interface subsurface_implementation;
735 
subsurface_from_resource(struct wl_resource * resource)736 static struct wlr_subsurface *subsurface_from_resource(
737 		struct wl_resource *resource) {
738 	assert(wl_resource_instance_of(resource, &wl_subsurface_interface,
739 		&subsurface_implementation));
740 	return wl_resource_get_user_data(resource);
741 }
742 
subsurface_resource_destroy(struct wl_resource * resource)743 static void subsurface_resource_destroy(struct wl_resource *resource) {
744 	struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
745 	wl_list_remove(wl_resource_get_link(resource));
746 	subsurface_destroy(subsurface);
747 }
748 
subsurface_handle_destroy(struct wl_client * client,struct wl_resource * resource)749 static void subsurface_handle_destroy(struct wl_client *client,
750 		struct wl_resource *resource) {
751 	wl_resource_destroy(resource);
752 }
753 
subsurface_handle_set_position(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y)754 static void subsurface_handle_set_position(struct wl_client *client,
755 		struct wl_resource *resource, int32_t x, int32_t y) {
756 	struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
757 	if (subsurface == NULL) {
758 		return;
759 	}
760 
761 	subsurface->pending.x = x;
762 	subsurface->pending.y = y;
763 }
764 
subsurface_find_sibling(struct wlr_subsurface * subsurface,struct wlr_surface * surface)765 static struct wlr_subsurface *subsurface_find_sibling(
766 		struct wlr_subsurface *subsurface, struct wlr_surface *surface) {
767 	struct wlr_surface *parent = subsurface->parent;
768 
769 	struct wlr_subsurface *sibling;
770 	wl_list_for_each(sibling, &parent->subsurfaces, parent_link) {
771 		if (sibling->surface == surface && sibling != subsurface) {
772 			return sibling;
773 		}
774 	}
775 
776 	return NULL;
777 }
778 
subsurface_handle_place_above(struct wl_client * client,struct wl_resource * resource,struct wl_resource * sibling_resource)779 static void subsurface_handle_place_above(struct wl_client *client,
780 		struct wl_resource *resource, struct wl_resource *sibling_resource) {
781 	struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
782 	if (subsurface == NULL) {
783 		return;
784 	}
785 
786 	struct wlr_surface *sibling_surface =
787 		wlr_surface_from_resource(sibling_resource);
788 	struct wlr_subsurface *sibling =
789 		subsurface_find_sibling(subsurface, sibling_surface);
790 
791 	if (!sibling) {
792 		wl_resource_post_error(subsurface->resource,
793 			WL_SUBSURFACE_ERROR_BAD_SURFACE,
794 			"%s: wl_surface@%" PRIu32 "is not a parent or sibling",
795 			"place_above", wl_resource_get_id(sibling_surface->resource));
796 		return;
797 	}
798 
799 	wl_list_remove(&subsurface->parent_pending_link);
800 	wl_list_insert(&sibling->parent_pending_link,
801 		&subsurface->parent_pending_link);
802 
803 	subsurface->reordered = true;
804 }
805 
subsurface_handle_place_below(struct wl_client * client,struct wl_resource * resource,struct wl_resource * sibling_resource)806 static void subsurface_handle_place_below(struct wl_client *client,
807 		struct wl_resource *resource, struct wl_resource *sibling_resource) {
808 	struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
809 	if (subsurface == NULL) {
810 		return;
811 	}
812 
813 	struct wlr_surface *sibling_surface =
814 		wlr_surface_from_resource(sibling_resource);
815 	struct wlr_subsurface *sibling =
816 		subsurface_find_sibling(subsurface, sibling_surface);
817 
818 	if (!sibling) {
819 		wl_resource_post_error(subsurface->resource,
820 			WL_SUBSURFACE_ERROR_BAD_SURFACE,
821 			"%s: wl_surface@%" PRIu32 " is not a parent or sibling",
822 			"place_below", wl_resource_get_id(sibling_surface->resource));
823 		return;
824 	}
825 
826 	wl_list_remove(&subsurface->parent_pending_link);
827 	wl_list_insert(sibling->parent_pending_link.prev,
828 		&subsurface->parent_pending_link);
829 
830 	subsurface->reordered = true;
831 }
832 
subsurface_handle_set_sync(struct wl_client * client,struct wl_resource * resource)833 static void subsurface_handle_set_sync(struct wl_client *client,
834 		struct wl_resource *resource) {
835 	struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
836 	if (subsurface == NULL) {
837 		return;
838 	}
839 
840 	subsurface->synchronized = true;
841 }
842 
subsurface_handle_set_desync(struct wl_client * client,struct wl_resource * resource)843 static void subsurface_handle_set_desync(struct wl_client *client,
844 		struct wl_resource *resource) {
845 	struct wlr_subsurface *subsurface = subsurface_from_resource(resource);
846 	if (subsurface == NULL) {
847 		return;
848 	}
849 
850 	if (subsurface->synchronized) {
851 		subsurface->synchronized = false;
852 
853 		if (!subsurface_is_synchronized(subsurface)) {
854 			// TODO: do a synchronized commit to flush the cache
855 			subsurface_parent_commit(subsurface, true);
856 		}
857 	}
858 }
859 
860 static const struct wl_subsurface_interface subsurface_implementation = {
861 	.destroy = subsurface_handle_destroy,
862 	.set_position = subsurface_handle_set_position,
863 	.place_above = subsurface_handle_place_above,
864 	.place_below = subsurface_handle_place_below,
865 	.set_sync = subsurface_handle_set_sync,
866 	.set_desync = subsurface_handle_set_desync,
867 };
868 
869 /**
870  * Checks if this subsurface needs to be marked as mapped. This can happen if:
871  * - The subsurface has a buffer
872  * - Its parent is mapped
873  */
subsurface_consider_map(struct wlr_subsurface * subsurface,bool check_parent)874 static void subsurface_consider_map(struct wlr_subsurface *subsurface,
875 		bool check_parent) {
876 	if (subsurface->mapped || !wlr_surface_has_buffer(subsurface->surface)) {
877 		return;
878 	}
879 
880 	if (check_parent) {
881 		if (subsurface->parent == NULL) {
882 			return;
883 		}
884 		if (wlr_surface_is_subsurface(subsurface->parent)) {
885 			struct wlr_subsurface *parent =
886 				wlr_subsurface_from_wlr_surface(subsurface->parent);
887 			if (parent == NULL || !parent->mapped) {
888 				return;
889 			}
890 		}
891 	}
892 
893 	// Now we can map the subsurface
894 	wlr_signal_emit_safe(&subsurface->events.map, subsurface);
895 	subsurface->mapped = true;
896 
897 	// Try mapping all children too
898 	struct wlr_subsurface *child;
899 	wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
900 		subsurface_consider_map(child, false);
901 	}
902 }
903 
subsurface_unmap(struct wlr_subsurface * subsurface)904 static void subsurface_unmap(struct wlr_subsurface *subsurface) {
905 	if (!subsurface->mapped) {
906 		return;
907 	}
908 
909 	wlr_signal_emit_safe(&subsurface->events.unmap, subsurface);
910 	subsurface->mapped = false;
911 
912 	// Unmap all children
913 	struct wlr_subsurface *child;
914 	wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
915 		subsurface_unmap(child);
916 	}
917 }
918 
subsurface_role_commit(struct wlr_surface * surface)919 static void subsurface_role_commit(struct wlr_surface *surface) {
920 	struct wlr_subsurface *subsurface =
921 		wlr_subsurface_from_wlr_surface(surface);
922 	if (subsurface == NULL) {
923 		return;
924 	}
925 
926 	if (subsurface->current.x != subsurface->pending.x ||
927 			subsurface->current.y != subsurface->pending.y) {
928 		// Subsurface has moved
929 		int dx = subsurface->current.x - subsurface->pending.x;
930 		int dy = subsurface->current.y - subsurface->pending.y;
931 
932 		subsurface->current.x = subsurface->pending.x;
933 		subsurface->current.y = subsurface->pending.y;
934 
935 		if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) {
936 			int tmp = dx;
937 			dx = dy;
938 			dy = tmp;
939 		}
940 
941 		pixman_region32_union_rect(&surface->buffer_damage,
942 			&surface->buffer_damage,
943 			dx * surface->previous.scale, dy * surface->previous.scale,
944 			surface->previous.buffer_width, surface->previous.buffer_height);
945 		pixman_region32_union_rect(&surface->buffer_damage,
946 			&surface->buffer_damage, 0, 0,
947 			surface->current.buffer_width, surface->current.buffer_height);
948 	}
949 
950 	subsurface_consider_map(subsurface, true);
951 }
952 
subsurface_role_precommit(struct wlr_surface * surface)953 static void subsurface_role_precommit(struct wlr_surface *surface) {
954 	struct wlr_subsurface *subsurface =
955 		wlr_subsurface_from_wlr_surface(surface);
956 	if (subsurface == NULL) {
957 		return;
958 	}
959 
960 	if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER &&
961 			surface->pending.buffer_resource == NULL) {
962 		// This is a NULL commit
963 		subsurface_unmap(subsurface);
964 	}
965 }
966 
967 const struct wlr_surface_role subsurface_role = {
968 	.name = "wl_subsurface",
969 	.commit = subsurface_role_commit,
970 	.precommit = subsurface_role_precommit,
971 };
972 
subsurface_handle_parent_destroy(struct wl_listener * listener,void * data)973 static void subsurface_handle_parent_destroy(struct wl_listener *listener,
974 		void *data) {
975 	struct wlr_subsurface *subsurface =
976 		wl_container_of(listener, subsurface, parent_destroy);
977 	subsurface_unmap(subsurface);
978 	wl_list_remove(&subsurface->parent_link);
979 	wl_list_remove(&subsurface->parent_pending_link);
980 	wl_list_remove(&subsurface->parent_destroy.link);
981 	subsurface->parent = NULL;
982 }
983 
subsurface_handle_surface_destroy(struct wl_listener * listener,void * data)984 static void subsurface_handle_surface_destroy(struct wl_listener *listener,
985 		void *data) {
986 	struct wlr_subsurface *subsurface =
987 		wl_container_of(listener, subsurface, surface_destroy);
988 	subsurface_destroy(subsurface);
989 }
990 
wlr_subsurface_create(struct wlr_surface * surface,struct wlr_surface * parent,uint32_t version,uint32_t id,struct wl_list * resource_list)991 struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
992 		struct wlr_surface *parent, uint32_t version, uint32_t id,
993 		struct wl_list *resource_list) {
994 	assert(version <= SUBSURFACE_VERSION);
995 
996 	struct wl_client *client = wl_resource_get_client(surface->resource);
997 
998 	struct wlr_subsurface *subsurface =
999 		calloc(1, sizeof(struct wlr_subsurface));
1000 	if (!subsurface) {
1001 		wl_client_post_no_memory(client);
1002 		return NULL;
1003 	}
1004 	surface_state_init(&subsurface->cached);
1005 	subsurface->synchronized = true;
1006 	subsurface->surface = surface;
1007 	subsurface->resource =
1008 		wl_resource_create(client, &wl_subsurface_interface, version, id);
1009 	if (subsurface->resource == NULL) {
1010 		surface_state_finish(&subsurface->cached);
1011 		free(subsurface);
1012 		wl_client_post_no_memory(client);
1013 		return NULL;
1014 	}
1015 	wl_resource_set_implementation(subsurface->resource,
1016 		&subsurface_implementation, subsurface,
1017 		subsurface_resource_destroy);
1018 
1019 	wl_signal_init(&subsurface->events.destroy);
1020 	wl_signal_init(&subsurface->events.map);
1021 	wl_signal_init(&subsurface->events.unmap);
1022 
1023 	wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy);
1024 	subsurface->surface_destroy.notify = subsurface_handle_surface_destroy;
1025 
1026 	// link parent
1027 	subsurface->parent = parent;
1028 	wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy);
1029 	subsurface->parent_destroy.notify = subsurface_handle_parent_destroy;
1030 	wl_list_insert(parent->subsurfaces.prev, &subsurface->parent_link);
1031 	wl_list_insert(parent->subsurface_pending_list.prev,
1032 		&subsurface->parent_pending_link);
1033 
1034 	surface->role_data = subsurface;
1035 
1036 	struct wl_list *resource_link = wl_resource_get_link(subsurface->resource);
1037 	if (resource_list != NULL) {
1038 		wl_list_insert(resource_list, resource_link);
1039 	} else {
1040 		wl_list_init(resource_link);
1041 	}
1042 
1043 	wlr_signal_emit_safe(&parent->events.new_subsurface, subsurface);
1044 
1045 	return subsurface;
1046 }
1047 
1048 
wlr_surface_get_root_surface(struct wlr_surface * surface)1049 struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) {
1050 	while (wlr_surface_is_subsurface(surface)) {
1051 		struct wlr_subsurface *subsurface =
1052 			wlr_subsurface_from_wlr_surface(surface);
1053 		if (subsurface == NULL) {
1054 			break;
1055 		}
1056 		surface = subsurface->parent;
1057 	}
1058 	return surface;
1059 }
1060 
wlr_surface_point_accepts_input(struct wlr_surface * surface,double sx,double sy)1061 bool wlr_surface_point_accepts_input(struct wlr_surface *surface,
1062 		double sx, double sy) {
1063 	return sx >= 0 && sx < surface->current.width &&
1064 		sy >= 0 && sy < surface->current.height &&
1065 		pixman_region32_contains_point(&surface->current.input, floor(sx), floor(sy), NULL);
1066 }
1067 
wlr_surface_surface_at(struct wlr_surface * surface,double sx,double sy,double * sub_x,double * sub_y)1068 struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface,
1069 		double sx, double sy, double *sub_x, double *sub_y) {
1070 	struct wlr_subsurface *subsurface;
1071 	wl_list_for_each_reverse(subsurface, &surface->subsurfaces, parent_link) {
1072 		double _sub_x = subsurface->current.x;
1073 		double _sub_y = subsurface->current.y;
1074 		struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface,
1075 			sx - _sub_x, sy - _sub_y, sub_x, sub_y);
1076 		if (sub != NULL) {
1077 			return sub;
1078 		}
1079 	}
1080 
1081 	if (wlr_surface_point_accepts_input(surface, sx, sy)) {
1082 		if (sub_x) {
1083 			*sub_x = sx;
1084 		}
1085 		if (sub_y) {
1086 			*sub_y = sy;
1087 		}
1088 		return surface;
1089 	}
1090 
1091 	return NULL;
1092 }
1093 
wlr_surface_send_enter(struct wlr_surface * surface,struct wlr_output * output)1094 void wlr_surface_send_enter(struct wlr_surface *surface,
1095 		struct wlr_output *output) {
1096 	struct wl_client *client = wl_resource_get_client(surface->resource);
1097 	struct wl_resource *resource;
1098 	wl_resource_for_each(resource, &output->resources) {
1099 		if (client == wl_resource_get_client(resource)) {
1100 			wl_surface_send_enter(surface->resource, resource);
1101 		}
1102 	}
1103 }
1104 
wlr_surface_send_leave(struct wlr_surface * surface,struct wlr_output * output)1105 void wlr_surface_send_leave(struct wlr_surface *surface,
1106 		struct wlr_output *output) {
1107 	struct wl_client *client = wl_resource_get_client(surface->resource);
1108 	struct wl_resource *resource;
1109 	wl_resource_for_each(resource, &output->resources) {
1110 		if (client == wl_resource_get_client(resource)) {
1111 			wl_surface_send_leave(surface->resource, resource);
1112 		}
1113 	}
1114 }
1115 
wlr_surface_send_frame_done(struct wlr_surface * surface,const struct timespec * when)1116 void wlr_surface_send_frame_done(struct wlr_surface *surface,
1117 		const struct timespec *when) {
1118 	struct wl_resource *resource, *tmp;
1119 	wl_resource_for_each_safe(resource, tmp,
1120 			&surface->current.frame_callback_list) {
1121 		wl_callback_send_done(resource, timespec_to_msec(when));
1122 		wl_resource_destroy(resource);
1123 	}
1124 }
1125 
surface_for_each_surface(struct wlr_surface * surface,int x,int y,wlr_surface_iterator_func_t iterator,void * user_data)1126 static void surface_for_each_surface(struct wlr_surface *surface, int x, int y,
1127 		wlr_surface_iterator_func_t iterator, void *user_data) {
1128 	iterator(surface, x, y, user_data);
1129 
1130 	struct wlr_subsurface *subsurface;
1131 	wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) {
1132 		struct wlr_subsurface_state *state = &subsurface->current;
1133 		int sx = state->x;
1134 		int sy = state->y;
1135 
1136 		surface_for_each_surface(subsurface->surface, x + sx, y + sy,
1137 			iterator, user_data);
1138 	}
1139 }
1140 
wlr_surface_for_each_surface(struct wlr_surface * surface,wlr_surface_iterator_func_t iterator,void * user_data)1141 void wlr_surface_for_each_surface(struct wlr_surface *surface,
1142 		wlr_surface_iterator_func_t iterator, void *user_data) {
1143 	surface_for_each_surface(surface, 0, 0, iterator, user_data);
1144 }
1145 
1146 struct bound_acc {
1147 	int32_t min_x, min_y;
1148 	int32_t max_x, max_y;
1149 };
1150 
handle_bounding_box_surface(struct wlr_surface * surface,int x,int y,void * data)1151 static void handle_bounding_box_surface(struct wlr_surface *surface,
1152 		int x, int y, void *data) {
1153 	struct bound_acc *acc = data;
1154 
1155 	acc->min_x = min(x, acc->min_x);
1156 	acc->min_y = min(y, acc->min_y);
1157 
1158 	acc->max_x = max(x + surface->current.width, acc->max_x);
1159 	acc->max_y = max(y + surface->current.height, acc->max_y);
1160 }
1161 
wlr_surface_get_extends(struct wlr_surface * surface,struct wlr_box * box)1162 void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) {
1163 	struct bound_acc acc = {
1164 		.min_x = 0,
1165 		.min_y = 0,
1166 		.max_x = surface->current.width,
1167 		.max_y = surface->current.height,
1168 	};
1169 
1170 	wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc);
1171 
1172 	box->x = acc.min_x;
1173 	box->y = acc.min_y;
1174 	box->width = acc.max_x - acc.min_x;
1175 	box->height = acc.max_y - acc.min_y;
1176 }
1177 
crop_region(pixman_region32_t * dst,pixman_region32_t * src,const struct wlr_box * box)1178 static void crop_region(pixman_region32_t *dst, pixman_region32_t *src,
1179 		const struct wlr_box *box) {
1180 	pixman_region32_intersect_rect(dst, src,
1181 		box->x, box->y, box->width, box->height);
1182 	pixman_region32_translate(dst, -box->x, -box->y);
1183 }
1184 
wlr_surface_get_effective_damage(struct wlr_surface * surface,pixman_region32_t * damage)1185 void wlr_surface_get_effective_damage(struct wlr_surface *surface,
1186 		pixman_region32_t *damage) {
1187 	pixman_region32_clear(damage);
1188 
1189 	// Transform and copy the buffer damage in terms of surface coordinates.
1190 	wlr_region_transform(damage, &surface->buffer_damage,
1191 		surface->current.transform, surface->current.buffer_width,
1192 		surface->current.buffer_height);
1193 	wlr_region_scale(damage, damage, 1.0 / (float)surface->current.scale);
1194 
1195 	if (surface->current.viewport.has_src) {
1196 		struct wlr_box src_box = {
1197 			.x = floor(surface->current.viewport.src.x),
1198 			.y = floor(surface->current.viewport.src.y),
1199 			.width = ceil(surface->current.viewport.src.width),
1200 			.height = ceil(surface->current.viewport.src.height),
1201 		};
1202 		crop_region(damage, damage, &src_box);
1203 	}
1204 	if (surface->current.viewport.has_dst) {
1205 		int src_width, src_height;
1206 		surface_state_viewport_src_size(&surface->current,
1207 			&src_width, &src_height);
1208 		float scale_x = (float)surface->current.viewport.dst_width / src_width;
1209 		float scale_y = (float)surface->current.viewport.dst_height / src_height;
1210 		wlr_region_scale_xy(damage, damage, scale_x, scale_y);
1211 	}
1212 
1213 	// On resize, damage the previous bounds of the surface. The current bounds
1214 	// have already been damaged in surface_update_damage.
1215 	if (surface->previous.width > surface->current.width ||
1216 			surface->previous.height > surface->current.height) {
1217 		pixman_region32_union_rect(damage, damage, 0, 0,
1218 			surface->previous.width, surface->previous.height);
1219 	}
1220 
1221 	// On move, damage where the surface was with its old dimensions.
1222 	if (surface->current.dx != 0 || surface->current.dy != 0) {
1223 		int prev_x = -surface->current.dx;
1224 		int prev_y = -surface->current.dy;
1225 		if ((surface->previous.transform & WL_OUTPUT_TRANSFORM_90) != 0) {
1226 			int temp = prev_x;
1227 			prev_x = prev_y;
1228 			prev_y = temp;
1229 		}
1230 		pixman_region32_union_rect(damage, damage, prev_x, prev_y,
1231 			surface->previous.width, surface->previous.height);
1232 	}
1233 }
1234 
wlr_surface_get_buffer_source_box(struct wlr_surface * surface,struct wlr_fbox * box)1235 void wlr_surface_get_buffer_source_box(struct wlr_surface *surface,
1236 		struct wlr_fbox *box) {
1237 	box->x = box->y = 0;
1238 	box->width = surface->current.buffer_width;
1239 	box->height = surface->current.buffer_height;
1240 
1241 	if (surface->current.viewport.has_src) {
1242 		box->x = surface->current.viewport.src.x * surface->current.scale;
1243 		box->y = surface->current.viewport.src.y * surface->current.scale;
1244 		box->width = surface->current.viewport.src.width * surface->current.scale;
1245 		box->height = surface->current.viewport.src.height * surface->current.scale;
1246 		if ((surface->current.transform & WL_OUTPUT_TRANSFORM_90) != 0) {
1247 			double tmp = box->x;
1248 			box->x = box->y;
1249 			box->y = tmp;
1250 
1251 			tmp = box->width;
1252 			box->width = box->height;
1253 			box->height = tmp;
1254 		}
1255 	}
1256 }
1257