1 /*
2  * Copyright © 2012 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "weston-test-client-helper.h"
32 
33 #define NUM_SUBSURFACES 3
34 
35 struct compound_surface {
36 	struct wl_subcompositor *subco;
37 	struct wl_surface *parent;
38 	struct wl_surface *child[NUM_SUBSURFACES];
39 	struct wl_subsurface *sub[NUM_SUBSURFACES];
40 };
41 
42 static struct wl_subcompositor *
get_subcompositor(struct client * client)43 get_subcompositor(struct client *client)
44 {
45 	struct global *g;
46 	struct global *global_sub = NULL;
47 	struct wl_subcompositor *sub;
48 
49 	wl_list_for_each(g, &client->global_list, link) {
50 		if (strcmp(g->interface, "wl_subcompositor"))
51 			continue;
52 
53 		if (global_sub)
54 			assert(0 && "multiple wl_subcompositor objects");
55 
56 		global_sub = g;
57 	}
58 
59 	assert(global_sub && "no wl_subcompositor found");
60 
61 	assert(global_sub->version == 1);
62 
63 	sub = wl_registry_bind(client->wl_registry, global_sub->name,
64 			       &wl_subcompositor_interface, 1);
65 	assert(sub);
66 
67 	return sub;
68 }
69 
70 static void
populate_compound_surface(struct compound_surface * com,struct client * client)71 populate_compound_surface(struct compound_surface *com, struct client *client)
72 {
73 	int i;
74 
75 	com->subco = get_subcompositor(client);
76 
77 	com->parent = wl_compositor_create_surface(client->wl_compositor);
78 
79 	for (i = 0; i < NUM_SUBSURFACES; i++) {
80 		com->child[i] =
81 			wl_compositor_create_surface(client->wl_compositor);
82 		com->sub[i] =
83 			wl_subcompositor_get_subsurface(com->subco,
84 							com->child[i],
85 							com->parent);
86 	}
87 }
88 
TEST(test_subsurface_basic_protocol)89 TEST(test_subsurface_basic_protocol)
90 {
91 	struct client *client;
92 	struct compound_surface com1;
93 	struct compound_surface com2;
94 
95 	client = create_client_and_test_surface(100, 50, 123, 77);
96 	assert(client);
97 
98 	populate_compound_surface(&com1, client);
99 	populate_compound_surface(&com2, client);
100 
101 	client_roundtrip(client);
102 }
103 
TEST(test_subsurface_position_protocol)104 TEST(test_subsurface_position_protocol)
105 {
106 	struct client *client;
107 	struct compound_surface com;
108 	int i;
109 
110 	client = create_client_and_test_surface(100, 50, 123, 77);
111 	assert(client);
112 
113 	populate_compound_surface(&com, client);
114 	for (i = 0; i < NUM_SUBSURFACES; i++)
115 		wl_subsurface_set_position(com.sub[i],
116 					   (i + 2) * 20, (i + 2) * 10);
117 
118 	client_roundtrip(client);
119 }
120 
TEST(test_subsurface_placement_protocol)121 TEST(test_subsurface_placement_protocol)
122 {
123 	struct client *client;
124 	struct compound_surface com;
125 
126 	client = create_client_and_test_surface(100, 50, 123, 77);
127 	assert(client);
128 
129 	populate_compound_surface(&com, client);
130 
131 	wl_subsurface_place_above(com.sub[0], com.child[1]);
132 	wl_subsurface_place_above(com.sub[1], com.parent);
133 	wl_subsurface_place_below(com.sub[2], com.child[0]);
134 	wl_subsurface_place_below(com.sub[1], com.parent);
135 
136 	client_roundtrip(client);
137 }
138 
TEST(test_subsurface_paradox)139 TEST(test_subsurface_paradox)
140 {
141 	struct client *client;
142 	struct wl_surface *parent;
143 	struct wl_subcompositor *subco;
144 
145 	client = create_client_and_test_surface(100, 50, 123, 77);
146 	assert(client);
147 
148 	subco = get_subcompositor(client);
149 	parent = wl_compositor_create_surface(client->wl_compositor);
150 
151 	/* surface is its own parent */
152 	wl_subcompositor_get_subsurface(subco, parent, parent);
153 
154 	expect_protocol_error(client, &wl_subcompositor_interface,
155 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
156 }
157 
TEST(test_subsurface_identical_link)158 TEST(test_subsurface_identical_link)
159 {
160 	struct client *client;
161 	struct compound_surface com;
162 
163 	client = create_client_and_test_surface(100, 50, 123, 77);
164 	assert(client);
165 
166 	populate_compound_surface(&com, client);
167 
168 	/* surface is already a subsurface */
169 	wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
170 
171 	expect_protocol_error(client, &wl_subcompositor_interface,
172 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
173 }
174 
TEST(test_subsurface_change_link)175 TEST(test_subsurface_change_link)
176 {
177 	struct client *client;
178 	struct compound_surface com;
179 	struct wl_surface *stranger;
180 
181 	client = create_client_and_test_surface(100, 50, 123, 77);
182 	assert(client);
183 
184 	stranger = wl_compositor_create_surface(client->wl_compositor);
185 	populate_compound_surface(&com, client);
186 
187 	/* surface is already a subsurface */
188 	wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
189 
190 	expect_protocol_error(client, &wl_subcompositor_interface,
191 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
192 }
193 
TEST(test_subsurface_nesting)194 TEST(test_subsurface_nesting)
195 {
196 	struct client *client;
197 	struct compound_surface com;
198 	struct wl_surface *stranger;
199 
200 	client = create_client_and_test_surface(100, 50, 123, 77);
201 	assert(client);
202 
203 	stranger = wl_compositor_create_surface(client->wl_compositor);
204 	populate_compound_surface(&com, client);
205 
206 	/* parent is a sub-surface */
207 	wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
208 
209 	client_roundtrip(client);
210 }
211 
TEST(test_subsurface_nesting_parent)212 TEST(test_subsurface_nesting_parent)
213 {
214 	struct client *client;
215 	struct compound_surface com;
216 	struct wl_surface *stranger;
217 
218 	client = create_client_and_test_surface(100, 50, 123, 77);
219 	assert(client);
220 
221 	stranger = wl_compositor_create_surface(client->wl_compositor);
222 	populate_compound_surface(&com, client);
223 
224 	/* surface is already a parent */
225 	wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
226 
227 	client_roundtrip(client);
228 }
229 
TEST(test_subsurface_loop_paradox)230 TEST(test_subsurface_loop_paradox)
231 {
232 	struct client *client;
233 	struct wl_surface *surface[3];
234 	struct wl_subcompositor *subco;
235 
236 	client = create_client_and_test_surface(100, 50, 123, 77);
237 	assert(client);
238 
239 	subco = get_subcompositor(client);
240 	surface[0] = wl_compositor_create_surface(client->wl_compositor);
241 	surface[1] = wl_compositor_create_surface(client->wl_compositor);
242 	surface[2] = wl_compositor_create_surface(client->wl_compositor);
243 
244 	/* create a nesting loop */
245 	wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
246 	wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
247 	wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
248 
249 	expect_protocol_error(client, &wl_subcompositor_interface,
250 			      WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE);
251 }
252 
TEST(test_subsurface_place_above_stranger)253 TEST(test_subsurface_place_above_stranger)
254 {
255 	struct client *client;
256 	struct compound_surface com;
257 	struct wl_surface *stranger;
258 
259 	client = create_client_and_test_surface(100, 50, 123, 77);
260 	assert(client);
261 
262 	stranger = wl_compositor_create_surface(client->wl_compositor);
263 	populate_compound_surface(&com, client);
264 
265 	/* bad sibling */
266 	wl_subsurface_place_above(com.sub[0], stranger);
267 
268 	expect_protocol_error(client, &wl_subsurface_interface,
269 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
270 }
271 
TEST(test_subsurface_place_below_stranger)272 TEST(test_subsurface_place_below_stranger)
273 {
274 	struct client *client;
275 	struct compound_surface com;
276 	struct wl_surface *stranger;
277 
278 	client = create_client_and_test_surface(100, 50, 123, 77);
279 	assert(client);
280 
281 	stranger = wl_compositor_create_surface(client->wl_compositor);
282 	populate_compound_surface(&com, client);
283 
284 	/* bad sibling */
285 	wl_subsurface_place_below(com.sub[0], stranger);
286 
287 	expect_protocol_error(client, &wl_subsurface_interface,
288 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
289 }
290 
TEST(test_subsurface_place_above_foreign)291 TEST(test_subsurface_place_above_foreign)
292 {
293 	struct client *client;
294 	struct compound_surface com1;
295 	struct compound_surface com2;
296 
297 	client = create_client_and_test_surface(100, 50, 123, 77);
298 	assert(client);
299 
300 	populate_compound_surface(&com1, client);
301 	populate_compound_surface(&com2, client);
302 
303 	/* bad sibling */
304 	wl_subsurface_place_above(com1.sub[0], com2.child[0]);
305 
306 	expect_protocol_error(client, &wl_subsurface_interface,
307 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
308 }
309 
TEST(test_subsurface_place_below_foreign)310 TEST(test_subsurface_place_below_foreign)
311 {
312 	struct client *client;
313 	struct compound_surface com1;
314 	struct compound_surface com2;
315 
316 	client = create_client_and_test_surface(100, 50, 123, 77);
317 	assert(client);
318 
319 	populate_compound_surface(&com1, client);
320 	populate_compound_surface(&com2, client);
321 
322 	/* bad sibling */
323 	wl_subsurface_place_below(com1.sub[0], com2.child[0]);
324 
325 	expect_protocol_error(client, &wl_subsurface_interface,
326 			      WL_SUBSURFACE_ERROR_BAD_SURFACE);
327 }
328 
TEST(test_subsurface_destroy_protocol)329 TEST(test_subsurface_destroy_protocol)
330 {
331 	struct client *client;
332 	struct compound_surface com;
333 
334 	client = create_client_and_test_surface(100, 50, 123, 77);
335 	assert(client);
336 
337 	populate_compound_surface(&com, client);
338 
339 	/* not needed anymore */
340 	wl_subcompositor_destroy(com.subco);
341 
342 	/* detach child from parent */
343 	wl_subsurface_destroy(com.sub[0]);
344 
345 	/* destroy: child, parent */
346 	wl_surface_destroy(com.child[1]);
347 	wl_surface_destroy(com.parent);
348 
349 	/* destroy: parent, child */
350 	wl_surface_destroy(com.child[2]);
351 
352 	/* destroy: sub, child */
353 	wl_surface_destroy(com.child[0]);
354 
355 	/* 2x destroy: child, sub */
356 	wl_subsurface_destroy(com.sub[2]);
357 	wl_subsurface_destroy(com.sub[1]);
358 
359 	client_roundtrip(client);
360 }
361 
362 static void
create_subsurface_tree(struct client * client,struct wl_surface ** surfs,struct wl_subsurface ** subs,int n)363 create_subsurface_tree(struct client *client, struct wl_surface **surfs,
364 		       struct wl_subsurface **subs, int n)
365 {
366 	struct wl_subcompositor *subco;
367 	int i;
368 
369 	subco = get_subcompositor(client);
370 
371 	for (i = 0; i < n; i++)
372 		surfs[i] = wl_compositor_create_surface(client->wl_compositor);
373 
374 	/*
375 	 * The tree of sub-surfaces:
376 	 *                            0
377 	 *                           / \
378 	 *                          1   2 - 10
379 	 *                         / \  |\
380 	 *                        3   5 9 6
381 	 *                       /       / \
382 	 *                      4       7   8
383 	 * Surface 0 has no wl_subsurface, others do.
384 	 */
385 
386 	switch (n) {
387 	default:
388 		assert(0);
389 		break;
390 
391 #define SUB_LINK(s,p) \
392 	subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
393 
394 	case 11:
395 		SUB_LINK(10, 2);
396 	case 10:
397 		SUB_LINK(9, 2);
398 	case 9:
399 		SUB_LINK(8, 6);
400 	case 8:
401 		SUB_LINK(7, 6);
402 	case 7:
403 		SUB_LINK(6, 2);
404 	case 6:
405 		SUB_LINK(5, 1);
406 	case 5:
407 		SUB_LINK(4, 3);
408 	case 4:
409 		SUB_LINK(3, 1);
410 	case 3:
411 		SUB_LINK(2, 0);
412 	case 2:
413 		SUB_LINK(1, 0);
414 
415 #undef SUB_LINK
416 	};
417 }
418 
419 static void
destroy_subsurface_tree(struct wl_surface ** surfs,struct wl_subsurface ** subs,int n)420 destroy_subsurface_tree(struct wl_surface **surfs,
421 			struct wl_subsurface **subs, int n)
422 {
423 	int i;
424 
425 	for (i = n; i-- > 0; ) {
426 		if (surfs[i])
427 			wl_surface_destroy(surfs[i]);
428 
429 		if (subs[i])
430 			wl_subsurface_destroy(subs[i]);
431 	}
432 }
433 
434 static int
has_dupe(int * cnt,int n)435 has_dupe(int *cnt, int n)
436 {
437 	int i;
438 
439 	for (i = 0; i < n; i++)
440 		if (cnt[i] == cnt[n])
441 			return 1;
442 
443 	return 0;
444 }
445 
446 /* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
447  */
448 #define NSTEPS 3
449 
450 struct permu_state {
451 	int set_size;
452 	int cnt[NSTEPS];
453 };
454 
455 static void
permu_init(struct permu_state * s,int set_size)456 permu_init(struct permu_state *s, int set_size)
457 {
458 	int i;
459 
460 	s->set_size = set_size;
461 	for (i = 0; i < NSTEPS; i++)
462 		s->cnt[i] = 0;
463 }
464 
465 static int
permu_next(struct permu_state * s)466 permu_next(struct permu_state *s)
467 {
468 	int k;
469 
470 	s->cnt[NSTEPS - 1]++;
471 
472 	while (1) {
473 		if (s->cnt[0] >= s->set_size) {
474 			return -1;
475 		}
476 
477 		for (k = 1; k < NSTEPS; k++) {
478 			if (s->cnt[k] >= s->set_size) {
479 				s->cnt[k - 1]++;
480 				s->cnt[k] = 0;
481 				break;
482 			}
483 
484 			if (has_dupe(s->cnt, k)) {
485 				s->cnt[k]++;
486 				break;
487 			}
488 		}
489 
490 		if (k == NSTEPS)
491 			return 0;
492 	}
493 }
494 
495 static void
destroy_permu_object(struct wl_surface ** surfs,struct wl_subsurface ** subs,int i)496 destroy_permu_object(struct wl_surface **surfs,
497 		     struct wl_subsurface **subs, int i)
498 {
499 	int h = (i + 1) / 2;
500 
501 	if (i & 1) {
502 		fprintf(stderr, " [sub  %2d]", h);
503 		wl_subsurface_destroy(subs[h]);
504 		subs[h] = NULL;
505 	} else {
506 		fprintf(stderr, " [surf %2d]", h);
507 		wl_surface_destroy(surfs[h]);
508 		surfs[h] = NULL;
509 	}
510 }
511 
TEST(test_subsurface_destroy_permutations)512 TEST(test_subsurface_destroy_permutations)
513 {
514 	/*
515 	 * Test wl_surface and wl_subsurface destruction orders in a
516 	 * complex tree of sub-surfaces.
517 	 *
518 	 * In the tree of sub-surfaces, go through every possible
519 	 * permutation of destroying all wl_surface and wl_subsurface
520 	 * objects. Execpt, to limit running time to a reasonable level,
521 	 * execute only the first NSTEPS destructions from each
522 	 * permutation, and ignore identical cases.
523 	 */
524 
525 	const int test_size = 11;
526 	struct client *client;
527 	struct wl_surface *surfs[test_size];
528 	struct wl_subsurface *subs[test_size];
529 	struct permu_state per;
530 	int counter = 0;
531 	int i;
532 
533 	client = create_client_and_test_surface(100, 50, 123, 77);
534 	assert(client);
535 
536 	permu_init(&per, test_size * 2 - 1);
537 	while (permu_next(&per) != -1) {
538 		/* for each permutation of NSTEPS out of test_size */
539 		memset(surfs, 0, sizeof surfs);
540 		memset(subs, 0, sizeof subs);
541 
542 		create_subsurface_tree(client, surfs, subs, test_size);
543 
544 		fprintf(stderr, "permu");
545 
546 		for (i = 0; i < NSTEPS; i++)
547 			fprintf(stderr, " %2d", per.cnt[i]);
548 
549 		for (i = 0; i < NSTEPS; i++)
550 			destroy_permu_object(surfs, subs, per.cnt[i]);
551 
552 		fprintf(stderr, "\n");
553 		client_roundtrip(client);
554 
555 		destroy_subsurface_tree(surfs, subs, test_size);
556 		counter++;
557 	}
558 
559 	client_roundtrip(client);
560 	fprintf(stderr, "tried %d destroy permutations\n", counter);
561 }
562