• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011 Intel Corporation
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 <stdlib.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <math.h>
33 #include <inttypes.h>
34 
35 #include <unistd.h>
36 #include <fcntl.h>
37 
38 #include <libweston/libweston.h>
39 #include "libweston-internal.h"
40 #include "shared/helpers.h"
41 #include "shared/timespec-util.h"
42 
43 WL_EXPORT void
weston_spring_init(struct weston_spring * spring,double k,double current,double target)44 weston_spring_init(struct weston_spring *spring,
45 		   double k, double current, double target)
46 {
47 	spring->k = k;
48 	spring->friction = 400.0;
49 	spring->current = current;
50 	spring->previous = current;
51 	spring->target = target;
52 	spring->clip = WESTON_SPRING_OVERSHOOT;
53 	spring->min = 0.0;
54 	spring->max = 1.0;
55 }
56 
57 WL_EXPORT void
weston_spring_update(struct weston_spring * spring,const struct timespec * time)58 weston_spring_update(struct weston_spring *spring, const struct timespec *time)
59 {
60 	double force, v, current, step;
61 
62 	/* Limit the number of executions of the loop below by ensuring that
63 	 * the timestamp for last update of the spring is no more than 1s ago.
64 	 * This handles the case where time moves backwards or forwards in
65 	 * large jumps.
66 	 */
67 	if (timespec_sub_to_msec(time, &spring->timestamp) > 1000) {
68 		weston_log("unexpectedly large timestamp jump "
69 			   "(from %" PRId64 " to %" PRId64 ")\n",
70 			   timespec_to_msec(&spring->timestamp),
71 			   timespec_to_msec(time));
72 		timespec_add_msec(&spring->timestamp, time, -1000);
73 	}
74 
75 	step = 0.01;
76 	while (4 < timespec_sub_to_msec(time, &spring->timestamp)) {
77 		current = spring->current;
78 		v = current - spring->previous;
79 		force = spring->k * (spring->target - current) / 10.0 +
80 			(spring->previous - current) - v * spring->friction;
81 
82 		spring->current =
83 			current + (current - spring->previous) +
84 			force * step * step;
85 		spring->previous = current;
86 
87 		switch (spring->clip) {
88 		case WESTON_SPRING_OVERSHOOT:
89 			break;
90 
91 		case WESTON_SPRING_CLAMP:
92 			if (spring->current > spring->max) {
93 				spring->current = spring->max;
94 				spring->previous = spring->max;
95 			} else if (spring->current < 0.0) {
96 				spring->current = spring->min;
97 				spring->previous = spring->min;
98 			}
99 			break;
100 
101 		case WESTON_SPRING_BOUNCE:
102 			if (spring->current > spring->max) {
103 				spring->current =
104 					2 * spring->max - spring->current;
105 				spring->previous =
106 					2 * spring->max - spring->previous;
107 			} else if (spring->current < spring->min) {
108 				spring->current =
109 					2 * spring->min - spring->current;
110 				spring->previous =
111 					2 * spring->min - spring->previous;
112 			}
113 			break;
114 		}
115 
116 		timespec_add_msec(&spring->timestamp, &spring->timestamp, 4);
117 	}
118 }
119 
120 WL_EXPORT int
weston_spring_done(struct weston_spring * spring)121 weston_spring_done(struct weston_spring *spring)
122 {
123 	return fabs(spring->previous - spring->target) < 0.002 &&
124 		fabs(spring->current - spring->target) < 0.002;
125 }
126 
127 typedef	void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
128 
129 struct weston_view_animation {
130 	struct weston_view *view;
131 	struct weston_animation animation;
132 	struct weston_spring spring;
133 	struct weston_transform transform;
134 	struct wl_listener listener;
135 	float start, stop;
136 	weston_view_animation_frame_func_t frame;
137 	weston_view_animation_frame_func_t reset;
138 	weston_view_animation_done_func_t done;
139 	void *data;
140 	void *private;
141 };
142 
143 WL_EXPORT void
weston_view_animation_destroy(struct weston_view_animation * animation)144 weston_view_animation_destroy(struct weston_view_animation *animation)
145 {
146 	wl_list_remove(&animation->animation.link);
147 	wl_list_remove(&animation->listener.link);
148 	wl_list_remove(&animation->transform.link);
149 	if (animation->reset)
150 		animation->reset(animation);
151 	weston_view_geometry_dirty(animation->view);
152 	if (animation->done)
153 		animation->done(animation, animation->data);
154 	free(animation);
155 }
156 
157 static void
handle_animation_view_destroy(struct wl_listener * listener,void * data)158 handle_animation_view_destroy(struct wl_listener *listener, void *data)
159 {
160 	struct weston_view_animation *animation =
161 		container_of(listener,
162 			     struct weston_view_animation, listener);
163 
164 	weston_view_animation_destroy(animation);
165 }
166 
167 static void
weston_view_animation_frame(struct weston_animation * base,struct weston_output * output,const struct timespec * time)168 weston_view_animation_frame(struct weston_animation *base,
169 			    struct weston_output *output,
170 			    const struct timespec *time)
171 {
172 	struct weston_view_animation *animation =
173 		container_of(base,
174 			     struct weston_view_animation, animation);
175 	struct weston_compositor *compositor =
176 		animation->view->surface->compositor;
177 
178 	if (base->frame_counter <= 1)
179 		animation->spring.timestamp = *time;
180 
181 	weston_spring_update(&animation->spring, time);
182 
183 	if (weston_spring_done(&animation->spring)) {
184 		weston_view_schedule_repaint(animation->view);
185 		weston_view_animation_destroy(animation);
186 		return;
187 	}
188 
189 	if (animation->frame)
190 		animation->frame(animation);
191 
192 	weston_view_geometry_dirty(animation->view);
193 	weston_view_schedule_repaint(animation->view);
194 
195 	/* The view's output_mask will be zero if its position is
196 	 * offscreen. Animations should always run but as they are also
197 	 * run off the repaint cycle, if there's nothing to repaint
198 	 * the animation stops running. Therefore if we catch this situation
199 	 * and schedule a repaint on all outputs it will be avoided.
200 	 */
201 	if (animation->view->output_mask == 0)
202 		weston_compositor_schedule_repaint(compositor);
203 }
204 
205 static void
idle_animation_destroy(void * data)206 idle_animation_destroy(void *data)
207 {
208 	struct weston_view_animation *animation = data;
209 
210 	weston_view_animation_destroy(animation);
211 }
212 
213 static struct weston_view_animation *
weston_view_animation_create(struct weston_view * view,float start,float stop,weston_view_animation_frame_func_t frame,weston_view_animation_frame_func_t reset,weston_view_animation_done_func_t done,void * data,void * private)214 weston_view_animation_create(struct weston_view *view,
215 			     float start, float stop,
216 			     weston_view_animation_frame_func_t frame,
217 			     weston_view_animation_frame_func_t reset,
218 			     weston_view_animation_done_func_t done,
219 			     void *data,
220 			     void *private)
221 {
222 	struct weston_view_animation *animation;
223 	struct weston_compositor *ec = view->surface->compositor;
224 	struct wl_event_loop *loop;
225 
226 	animation = malloc(sizeof *animation);
227 	if (!animation)
228 		return NULL;
229 
230 	animation->view = view;
231 	animation->frame = frame;
232 	animation->reset = reset;
233 	animation->done = done;
234 	animation->data = data;
235 	animation->start = start;
236 	animation->stop = stop;
237 	animation->private = private;
238 
239 	weston_matrix_init(&animation->transform.matrix);
240 	wl_list_insert(&view->geometry.transformation_list,
241 		       &animation->transform.link);
242 
243 	animation->animation.frame = weston_view_animation_frame;
244 
245 	animation->listener.notify = handle_animation_view_destroy;
246 	wl_signal_add(&view->destroy_signal, &animation->listener);
247 
248 	if (view->output) {
249 		wl_list_insert(&view->output->animation_list,
250 			       &animation->animation.link);
251 	} else {
252 		wl_list_init(&animation->animation.link);
253 		loop = wl_display_get_event_loop(ec->wl_display);
254 		wl_event_loop_add_idle(loop, idle_animation_destroy, animation);
255 	}
256 
257 	return animation;
258 }
259 
260 static void
weston_view_animation_run(struct weston_view_animation * animation)261 weston_view_animation_run(struct weston_view_animation *animation)
262 {
263 	struct timespec zero_time = { 0 };
264 
265 	animation->animation.frame_counter = 0;
266 	weston_view_animation_frame(&animation->animation, NULL, &zero_time);
267 }
268 
269 static void
reset_alpha(struct weston_view_animation * animation)270 reset_alpha(struct weston_view_animation *animation)
271 {
272 	struct weston_view *view = animation->view;
273 
274 	view->alpha = animation->stop;
275 }
276 
277 static void
zoom_frame(struct weston_view_animation * animation)278 zoom_frame(struct weston_view_animation *animation)
279 {
280 	struct weston_view *es = animation->view;
281 	float scale;
282 
283 	scale = animation->start +
284 		(animation->stop - animation->start) *
285 		animation->spring.current;
286 	weston_matrix_init(&animation->transform.matrix);
287 	weston_matrix_translate(&animation->transform.matrix,
288 				-0.5f * es->surface->width,
289 				-0.5f * es->surface->height, 0);
290 	weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
291 	weston_matrix_translate(&animation->transform.matrix,
292 				0.5f * es->surface->width,
293 				0.5f * es->surface->height, 0);
294 
295 	es->alpha = animation->spring.current;
296 	if (es->alpha > 1.0)
297 		es->alpha = 1.0;
298 }
299 
300 WL_EXPORT struct weston_view_animation *
weston_zoom_run(struct weston_view * view,float start,float stop,weston_view_animation_done_func_t done,void * data)301 weston_zoom_run(struct weston_view *view, float start, float stop,
302 		weston_view_animation_done_func_t done, void *data)
303 {
304 	struct weston_view_animation *zoom;
305 
306 	zoom = weston_view_animation_create(view, start, stop,
307 					    zoom_frame, reset_alpha,
308 					    done, data, NULL);
309 
310 	if (zoom == NULL)
311 		return NULL;
312 
313 	weston_spring_init(&zoom->spring, 300.0, start, stop);
314 	zoom->spring.friction = 1400;
315 	zoom->spring.previous = start - (stop - start) * 0.03;
316 
317 	weston_view_animation_run(zoom);
318 
319 	return zoom;
320 }
321 
322 static void
fade_frame(struct weston_view_animation * animation)323 fade_frame(struct weston_view_animation *animation)
324 {
325 	if (animation->spring.current > 0.999)
326 		animation->view->alpha = 1;
327 	else if (animation->spring.current < 0.001 )
328 		animation->view->alpha = 0;
329 	else
330 		animation->view->alpha = animation->spring.current;
331 }
332 
333 WL_EXPORT struct weston_view_animation *
weston_fade_run(struct weston_view * view,float start,float end,float k,weston_view_animation_done_func_t done,void * data)334 weston_fade_run(struct weston_view *view,
335 		float start, float end, float k,
336 		weston_view_animation_done_func_t done, void *data)
337 {
338 	struct weston_view_animation *fade;
339 
340 	fade = weston_view_animation_create(view, start, end,
341 					    fade_frame, reset_alpha,
342 					    done, data, NULL);
343 
344 	if (fade == NULL)
345 		return NULL;
346 
347 	weston_spring_init(&fade->spring, 1000.0, start, end);
348 	fade->spring.friction = 4000;
349 	fade->spring.previous = start - (end - start) * 0.1;
350 
351 	view->alpha = start;
352 
353 	weston_view_animation_run(fade);
354 
355 	return fade;
356 }
357 
358 WL_EXPORT void
weston_fade_update(struct weston_view_animation * fade,float target)359 weston_fade_update(struct weston_view_animation *fade, float target)
360 {
361 	fade->spring.target = target;
362 	fade->stop = target;
363 }
364 
365 static void
stable_fade_frame(struct weston_view_animation * animation)366 stable_fade_frame(struct weston_view_animation *animation)
367 {
368 	struct weston_view *back_view;
369 
370 	if (animation->spring.current > 0.999)
371 		animation->view->alpha = 1;
372 	else if (animation->spring.current < 0.001 )
373 		animation->view->alpha = 0;
374 	else
375 		animation->view->alpha = animation->spring.current;
376 
377 	back_view = (struct weston_view *) animation->private;
378 	back_view->alpha =
379 		(animation->spring.target - animation->view->alpha) /
380 		(1.0 - animation->view->alpha);
381 	weston_view_geometry_dirty(back_view);
382 }
383 
384 WL_EXPORT struct weston_view_animation *
weston_stable_fade_run(struct weston_view * front_view,float start,struct weston_view * back_view,float end,weston_view_animation_done_func_t done,void * data)385 weston_stable_fade_run(struct weston_view *front_view, float start,
386 		struct weston_view *back_view, float end,
387 		weston_view_animation_done_func_t done, void *data)
388 {
389 	struct weston_view_animation *fade;
390 
391 	fade = weston_view_animation_create(front_view, 0, 0,
392 					    stable_fade_frame, NULL,
393 					    done, data, back_view);
394 
395 	if (fade == NULL)
396 		return NULL;
397 
398 	weston_spring_init(&fade->spring, 400, start, end);
399 	fade->spring.friction = 1150;
400 
401 	front_view->alpha = start;
402 	back_view->alpha = end;
403 
404 	weston_view_animation_run(fade);
405 
406 	return fade;
407 }
408 
409 static void
slide_frame(struct weston_view_animation * animation)410 slide_frame(struct weston_view_animation *animation)
411 {
412 	float scale;
413 
414 	scale = animation->start +
415 		(animation->stop - animation->start) *
416 		animation->spring.current;
417 	weston_matrix_init(&animation->transform.matrix);
418 	weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
419 }
420 
421 WL_EXPORT struct weston_view_animation *
weston_slide_run(struct weston_view * view,float start,float stop,weston_view_animation_done_func_t done,void * data)422 weston_slide_run(struct weston_view *view, float start, float stop,
423 		 weston_view_animation_done_func_t done, void *data)
424 {
425 	struct weston_view_animation *animation;
426 
427 	animation = weston_view_animation_create(view, start, stop,
428 					      slide_frame, NULL, done,
429 					      data, NULL);
430 	if (!animation)
431 		return NULL;
432 
433 	weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
434 	animation->spring.friction = 600;
435 	animation->spring.clip = WESTON_SPRING_BOUNCE;
436 
437 	weston_view_animation_run(animation);
438 
439 	return animation;
440 }
441 
442 struct weston_move_animation {
443 	int dx;
444 	int dy;
445 	bool reverse;
446 	bool scale;
447 	weston_view_animation_done_func_t done;
448 };
449 
450 static void
move_frame(struct weston_view_animation * animation)451 move_frame(struct weston_view_animation *animation)
452 {
453 	struct weston_move_animation *move = animation->private;
454 	float scale;
455 	float progress = animation->spring.current;
456 
457 	if (move->reverse)
458 		progress = 1.0 - progress;
459 
460 	scale = animation->start +
461                 (animation->stop - animation->start) *
462                 progress;
463 	weston_matrix_init(&animation->transform.matrix);
464 	if (move->scale)
465 		weston_matrix_scale(&animation->transform.matrix, scale, scale,
466 				    1.0f);
467 	weston_matrix_translate(&animation->transform.matrix,
468                                 move->dx * progress, move->dy * progress,
469 				0);
470 }
471 
472 static void
move_done(struct weston_view_animation * animation,void * data)473 move_done(struct weston_view_animation *animation, void *data)
474 {
475 	struct weston_move_animation *move = animation->private;
476 
477 	if (move->done)
478 		move->done(animation, data);
479 
480 	free(move);
481 }
482 
483 static struct weston_view_animation *
weston_move_scale_run_internal(struct weston_view * view,int dx,int dy,float start,float end,bool reverse,bool scale,weston_view_animation_done_func_t done,void * data)484 weston_move_scale_run_internal(struct weston_view *view, int dx, int dy,
485 			       float start, float end, bool reverse, bool scale,
486 			       weston_view_animation_done_func_t done,
487 			       void *data)
488 {
489 	struct weston_move_animation *move;
490 	struct weston_view_animation *animation;
491 
492 	move = malloc(sizeof(*move));
493 	if (!move)
494 		return NULL;
495 	move->dx = dx;
496 	move->dy = dy;
497 	move->reverse = reverse;
498 	move->scale = scale;
499 	move->done = done;
500 
501 	animation = weston_view_animation_create(view, start, end, move_frame,
502 						 NULL, move_done, data, move);
503 
504 	if (animation == NULL){
505 		free(move);
506 		return NULL;
507 	}
508 
509 	weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
510 	animation->spring.friction = 1150;
511 
512 	weston_view_animation_run(animation);
513 
514 	return animation;
515 }
516 
517 WL_EXPORT struct weston_view_animation *
weston_move_scale_run(struct weston_view * view,int dx,int dy,float start,float end,bool reverse,weston_view_animation_done_func_t done,void * data)518 weston_move_scale_run(struct weston_view *view, int dx, int dy,
519 		      float start, float end, bool reverse,
520 		      weston_view_animation_done_func_t done, void *data)
521 {
522 	return weston_move_scale_run_internal(view, dx, dy, start, end, reverse,
523 					      true, done, data);
524 }
525 
526 WL_EXPORT struct weston_view_animation *
weston_move_run(struct weston_view * view,int dx,int dy,float start,float end,bool reverse,weston_view_animation_done_func_t done,void * data)527 weston_move_run(struct weston_view *view, int dx, int dy,
528 		float start, float end, bool reverse,
529 		weston_view_animation_done_func_t done, void *data)
530 {
531 	return weston_move_scale_run_internal(view, dx, dy, start, end, reverse,
532 					      false, done, data);
533 }
534