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