1 /*
2 ** Copyright (C) 2009 Tadej Borovšak <tadeboro@gmail.com>
3 ** Copyright (C) 2010 Robert Chéramy <robert@cheramy.net>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 #include "subtitles.h"
21 #include "support.h"
22 
23 /* Border width around image (no text is placed there) */
24 #define BORDER 20
25 
26 /* Wrap width for subtitles (fraction of image size) */
27 #define WRAP_WIDTH 0.75
28 
29 /* ****************************************************************************
30  * Local declarations
31  * ************************************************************************* */
32 static void
33 img_calc_text_pos( gint      surface_w,
34 				   gint      surface_h,
35 				   gint      layout_w,
36 				   gint      layout_h,
37 				   ImgSubPos position,
38 				   gint     *posx,
39 				   gint     *posy );
40 
41 static void
42 img_text_ani_fade( cairo_t     *cr,
43 				   PangoLayout *layout,
44 				   gint         sw,
45 				   gint         sh,
46 				   gint         lw,
47 				   gint         lh,
48 				   gint         posx,
49 				   gint         posy,
50 				   gdouble      progress,
51 				   gdouble     *font_color,
52 				   gdouble     *font_bgcolor);
53 
54 static void
55 img_text_draw_layout( cairo_t     *cr,
56                       PangoLayout *layout,
57                       gint posx,
58                       gint posy,
59                       gdouble     *font_color,
60                       gdouble     *font_bgcolor);
61 
62 static void
63 img_text_from_left( cairo_t     *cr,
64 					PangoLayout *layout,
65  					gint         sw,
66  					gint         sh,
67  					gint         lw,
68  					gint         lh,
69  					gint         posx,
70  					gint         posy,
71  					gdouble      progress,
72                     gdouble     *font_color,
73                     gdouble     *font_bgcolor);
74 
75 static void
76 img_text_from_right( cairo_t     *cr,
77 					 PangoLayout *layout,
78  					 gint         sw,
79  					 gint         sh,
80  					 gint         lw,
81  					 gint         lh,
82  					 gint         posx,
83  					 gint         posy,
84  					 gdouble      progress,
85                      gdouble     *font_color,
86                      gdouble     *font_bgcolor);
87 
88 static void
89 img_text_from_top( cairo_t     *cr,
90 				   PangoLayout *layout,
91 				   gint         sw,
92 				   gint         sh,
93 				   gint         lw,
94 				   gint         lh,
95 				   gint         posx,
96 				   gint         posy,
97 				   gdouble      progress,
98                    gdouble     *font_color,
99                    gdouble     *font_bgcolor);
100 
101 static void
102 img_text_from_bottom( cairo_t     *cr,
103 					  PangoLayout *layout,
104 					  gint         sw,
105 					  gint         sh,
106   					  gint         lw,
107   					  gint         lh,
108   					  gint         posx,
109   					  gint         posy,
110   					  gdouble      progress,
111                       gdouble     *font_color,
112                       gdouble     *font_bgcolor);
113 
114 static void
115 img_text_grow( cairo_t     *cr,
116 			   PangoLayout *layout,
117 			   gint         sw,
118 			   gint         sh,
119 			   gint         lw,
120 			   gint         lh,
121 			   gint         posx,
122 			   gint         posy,
123 			   gdouble      progress,
124                gdouble     *font_color,
125                gdouble     *font_bgcolor);
126 
127 
128 /* ****************************************************************************
129  * Function definitions
130  * ************************************************************************* */
131 
132 /*
133  * img_get_text_animation_list:
134  * @animations: location to put list of available text animations
135  *
136  * This function is here to simplify accessing all available animations.
137  *
138  * Any newly added exporters should be listed in array returned by this function
139  * or Imagination WILL NOT create combo box entries for them.
140  *
141  * List that is placed in exporters parameter should be considered read-only and
142  * freed after usage with img_free_text_animation_list. If @animations is NULL,
143  * only number of available animations is returned.
144  *
145  * Return value: Size of list in animations.
146  */
147 gint
img_get_text_animation_list(TextAnimation ** animations)148 img_get_text_animation_list( TextAnimation **animations )
149 {
150 	TextAnimation *list;              /* List of all animations */
151 	gint           no_animations = 7; /* Number of animations */
152 	gint           i = 0;
153 
154 	if( animations )
155 	{
156 		/* Populate list */
157 		/* DO NOT SHUFFLE THIS LIST! ONLY ADD NEW ANIMATIONS AT THE END OF THE
158 		 * LIST OR LOADING OF OLD PROJECTS WON'T WORK PROPERLY!!!! */
159 		list = g_slice_alloc( sizeof( TextAnimation ) * no_animations );
160 
161 		/* No animation function (id = 0) */
162 		list[i].name   = g_strdup( _("None") );
163 		list[i].id     = i;
164 		list[i++].func = NULL;
165 
166 		list[i].name   = g_strdup( _("Fade") );
167 		list[i].id     = i;
168 		list[i++].func = img_text_ani_fade;
169 
170 		list[i].name   = g_strdup( _("Slide from left") );
171 		list[i].id     = i;
172 		list[i++].func = img_text_from_left;
173 
174 		list[i].name   = g_strdup( _("Slide from right") );
175 		list[i].id     = i;
176 		list[i++].func = img_text_from_right;
177 
178 		list[i].name   = g_strdup( _("Slide from top") );
179 		list[i].id     = i;
180 		list[i++].func = img_text_from_top;
181 
182 		list[i].name   = g_strdup( _("Slide from bottom") );
183 		list[i].id     = i;
184 		list[i++].func = img_text_from_bottom;
185 
186 		list[i].name   = g_strdup( _("Grow") );
187 		list[i].id     = i;
188 		list[i++].func = img_text_grow;
189 
190 		/* FIXME: Add more animations here.
191 		 *
192 		 * DO NOT FORGET TO UPDATE no_animations VARIABLE AT THE TOP OF THIS
193 		 * FUNCTION WHEN ADDING NEW ANIMATIONS!! */
194 
195 		*animations = list;
196 	}
197 
198 	return( no_animations );
199 }
200 
201 /*
202  * img_free_text_animation_list:
203  * @no_animations: number of animations in @animations
204  * @animations: array of TextAnimation structs
205  *
206  * This function takes care of freeing any memory allocated by
207  * img_get_text_animation_list function.
208  */
209 void
img_free_text_animation_list(gint no_animations,TextAnimation * animations)210 img_free_text_animation_list( gint           no_animations,
211 							  TextAnimation *animations )
212 {
213 	register gint i;
214 
215 	for( i = 0; i < no_animations; i++ )
216 		g_free( animations[i].name );
217 
218 	g_slice_free1( sizeof( TextAnimation ) * no_animations, animations );
219 }
220 
221 void
img_render_subtitle(cairo_t * cr,gint width,gint height,gdouble zoom,ImgSubPos position,ImgRelPlacing placing,gdouble factor,gdouble offx,gdouble offy,gchar * subtitle,PangoFontDescription * font_desc,gdouble * font_color,gdouble * font_bgcolor,TextAnimationFunc func,gdouble progress)222 img_render_subtitle( cairo_t              *cr,
223 					 gint                  width,
224 					 gint                  height,
225 					 gdouble               zoom,
226 					 ImgSubPos             position,
227 					 ImgRelPlacing         placing,
228 					 gdouble               factor,
229 					 gdouble               offx,
230 					 gdouble               offy,
231 					 gchar                *subtitle,
232 					 PangoFontDescription *font_desc,
233 					 gdouble              *font_color,
234                      gdouble              *font_bgcolor,
235                      TextAnimationFunc     func,
236 					 gdouble               progress )
237 {
238 	gint		 lw,     /* Layout width */
239 				 lh,     /* Layout height */
240 				 posx,   /* Final subtitle position */
241 				 posy;
242 	PangoLayout *layout;
243 
244 	/* Save cairo state */
245 	cairo_save( cr );
246 
247 	/* Transform cairo context to get proper text measurements */
248 	if( placing == IMG_REL_PLACING_ORIGINAL_IMAGE )
249 	{
250 		cairo_scale( cr, factor * zoom, factor * zoom );
251 		cairo_translate( cr, offx / factor, offy / factor );
252 	}
253 	else
254 		cairo_scale( cr, zoom, zoom );
255 
256 	/* Create pango layout and measure it */
257 	layout = pango_cairo_create_layout( cr );
258 	pango_layout_set_font_description( layout, font_desc );
259 	/* Disable wrapping
260 	pango_layout_set_wrap( layout, PANGO_WRAP_WORD );
261 	*/
262 	switch( position )
263 	{
264 		case IMG_SUB_POS_TOP_LEFT:
265 		case IMG_SUB_POS_MIDDLE_LEFT:
266 		case IMG_SUB_POS_BOTTOM_LEFT:
267 			pango_layout_set_alignment( layout, PANGO_ALIGN_LEFT );
268 			break;
269 
270 		case IMG_SUB_POS_TOP_CENTER:
271 		case IMG_SUB_POS_MIDDLE_CENTER:
272 		case IMG_SUB_POS_BOTTOM_CENTER:
273 			pango_layout_set_alignment( layout, PANGO_ALIGN_CENTER );
274 			break;
275 
276 		case IMG_SUB_POS_TOP_RIGHT:
277 		case IMG_SUB_POS_MIDDLE_RIGHT:
278 		case IMG_SUB_POS_BOTTOM_RIGHT:
279 			pango_layout_set_alignment( layout, PANGO_ALIGN_RIGHT );
280 			break;
281 	}
282 	pango_layout_set_text( layout, subtitle, -1 );
283 	pango_layout_get_size( layout, &lw, &lh );
284 	lw /= PANGO_SCALE;
285 
286 	/* Disable wrapping
287 	if( lw > ( width * WRAP_WIDTH ) )
288 	{
289 		pango_layout_set_width( layout, width * WRAP_WIDTH * PANGO_SCALE );
290 		pango_layout_get_size( layout, &lw, &lh );
291 		lw /= PANGO_SCALE;
292 	}
293 	*/
294 	lh /= PANGO_SCALE;
295 
296 	/* Calculate relative dimensions and final position of this subtitle */
297 	img_calc_text_pos( width, height, lw, lh, position, &posx, &posy );
298 
299 	/* Do animation */
300 	if( func )
301 		(*func)( cr, layout, width, height, lw, lh, posx, posy, progress, font_color, font_bgcolor );
302 	else
303 	{
304 		/* No animation renderer */
305         img_text_draw_layout(cr, layout, posx, posy, font_color, font_bgcolor);
306 	}
307 
308 	/* Destroy layout */
309 	g_object_unref( G_OBJECT( layout ) );
310 
311 	/* Restore cairo */
312 	cairo_restore( cr );
313 }
314 
315 static void
img_calc_text_pos(gint surface_w,gint surface_h,gint layout_w,gint layout_h,ImgSubPos position,gint * posx,gint * posy)316 img_calc_text_pos( gint      surface_w,
317 				   gint      surface_h,
318 				   gint      layout_w,
319 				   gint      layout_h,
320 				   ImgSubPos position,
321 				   gint     *posx,
322 				   gint     *posy )
323 {
324 	switch( position )
325 	{
326 		case IMG_SUB_POS_TOP_LEFT:
327 			*posx = BORDER;
328 			*posy = BORDER;
329 			break;
330 
331 		case IMG_SUB_POS_TOP_CENTER:
332 			*posx = ( surface_w - layout_w ) / 2;
333 			*posy = BORDER;
334 			break;
335 
336 		case IMG_SUB_POS_TOP_RIGHT:
337 			*posx = surface_w - BORDER - layout_w;
338 			*posy = BORDER;
339 			break;
340 
341 		case IMG_SUB_POS_MIDDLE_LEFT:
342 			*posx = BORDER;
343 			*posy = ( surface_h - layout_h ) / 2;
344 			break;
345 
346 		case IMG_SUB_POS_MIDDLE_CENTER:
347 			*posx = ( surface_w - layout_w ) / 2;
348 			*posy = ( surface_h - layout_h ) / 2;
349 			break;
350 
351 		case IMG_SUB_POS_MIDDLE_RIGHT:
352 			*posx = surface_w - BORDER - layout_w;
353 			*posy = ( surface_h - layout_h ) / 2;
354 			break;
355 
356 		case IMG_SUB_POS_BOTTOM_LEFT:
357 			*posx = BORDER;
358 			*posy = surface_h - BORDER - layout_h;
359 			break;
360 
361 		case IMG_SUB_POS_BOTTOM_CENTER:
362 			*posx = ( surface_w - layout_w ) / 2;
363 			*posy = surface_h - BORDER - layout_h;
364 			break;
365 
366 		case IMG_SUB_POS_BOTTOM_RIGHT:
367 			*posx = surface_w - BORDER - layout_w;
368 			*posy = surface_h - BORDER - layout_h;
369 			break;
370 	}
371 }
372 
373 
374 /* ****************************************************************************
375  * Text animation renderers
376  * ************************************************************************* */
377 static void
img_text_ani_fade(cairo_t * cr,PangoLayout * layout,gint sw,gint sh,gint lw,gint lh,gint posx,gint posy,gdouble progress,gdouble * font_color,gdouble * font_bgcolor)378 img_text_ani_fade( cairo_t     *cr,
379 				   PangoLayout *layout,
380 				   gint         sw,
381 				   gint         sh,
382 				   gint         lw,
383 				   gint         lh,
384 				   gint         posx,
385 				   gint         posy,
386 				   gdouble      progress,
387                    gdouble     *font_color,
388                    gdouble     *font_bgcolor)
389 {
390     gdouble  progress_font_color[4], progress_font_bgcolor[4];
391 
392 	/* Calculate colors */
393     progress_font_color[0] = font_color[0];
394     progress_font_color[1] = font_color[1];
395     progress_font_color[2] = font_color[2];
396     progress_font_color[3] = font_color[3] * progress;
397 
398     progress_font_bgcolor[0] = font_bgcolor[0];
399     progress_font_bgcolor[1] = font_bgcolor[1];
400     progress_font_bgcolor[2] = font_bgcolor[2];
401     progress_font_bgcolor[3] = font_bgcolor[3] * pow(progress, 6);
402 
403     /* Paint text */
404     img_text_draw_layout(cr, layout, posx, posy, progress_font_color, progress_font_bgcolor);
405 }
406 
407 static void
img_text_draw_layout(cairo_t * cr,PangoLayout * layout,gint posx,gint posy,gdouble * font_color,gdouble * font_bgcolor)408 img_text_draw_layout( cairo_t     *cr,
409                       PangoLayout *layout,
410                       gint         posx,
411                       gint         posy,
412                       gdouble     *font_color,
413                       gdouble     *font_bgcolor)
414 {
415     gint x,y;
416 
417     /* Draw the background border */
418     cairo_set_source_rgba(cr, font_bgcolor[0],
419                               font_bgcolor[1],
420                               font_bgcolor[2],
421                               font_bgcolor[3] );
422     for (x=-1; x <=1; x++)
423     {
424         for (y=-1; y<=1; y++)
425         {
426             cairo_move_to( cr, posx + x, posy + y );
427             pango_cairo_show_layout( cr, layout );
428         }
429     }
430 
431     /* Draw the subtitle */
432     /* Set source color */
433     cairo_set_source_rgba( cr, font_color[0],
434                                font_color[1],
435                                font_color[2],
436                                font_color[3] );
437 
438     /* Move to proper place and paint text */
439     cairo_move_to( cr, posx, posy );
440     pango_cairo_show_layout( cr, layout );
441 }
442 
443 static void
img_text_from_left(cairo_t * cr,PangoLayout * layout,gint sw,gint sh,gint lw,gint lh,gint posx,gint posy,gdouble progress,gdouble * font_color,gdouble * font_bgcolor)444 img_text_from_left( cairo_t     *cr,
445 					PangoLayout *layout,
446  					gint         sw,
447  					gint         sh,
448  					gint         lw,
449  					gint         lh,
450  					gint         posx,
451  					gint         posy,
452  					gdouble      progress,
453                     gdouble     *font_color,
454                     gdouble     *font_bgcolor)
455 {
456     img_text_draw_layout(cr, layout,
457                          posx * progress - lw * ( 1 - progress ),
458                          posy,
459                          font_color, font_bgcolor);
460 }
461 
462 static void
img_text_from_right(cairo_t * cr,PangoLayout * layout,gint sw,gint sh,gint lw,gint lh,gint posx,gint posy,gdouble progress,gdouble * font_color,gdouble * font_bgcolor)463 img_text_from_right( cairo_t     *cr,
464 					 PangoLayout *layout,
465  					 gint         sw,
466  					 gint         sh,
467  					 gint         lw,
468  					 gint         lh,
469  					 gint         posx,
470  					 gint         posy,
471  					 gdouble      progress,
472                      gdouble     *font_color,
473                      gdouble     *font_bgcolor)
474 {
475     img_text_draw_layout(cr, layout,
476                          posx * progress + sw * ( 1 - progress ),
477                          posy,
478                          font_color, font_bgcolor);
479 }
480 
481 static void
img_text_from_top(cairo_t * cr,PangoLayout * layout,gint sw,gint sh,gint lw,gint lh,gint posx,gint posy,gdouble progress,gdouble * font_color,gdouble * font_bgcolor)482 img_text_from_top( cairo_t     *cr,
483 				   PangoLayout *layout,
484 				   gint         sw,
485 				   gint         sh,
486 				   gint         lw,
487 				   gint         lh,
488 				   gint         posx,
489 				   gint         posy,
490 				   gdouble      progress,
491                    gdouble     *font_color,
492                    gdouble     *font_bgcolor)
493 {
494     img_text_draw_layout(cr, layout,
495                          posx,
496                          posy * progress - lh * ( 1 - progress ),
497                          font_color, font_bgcolor);
498 }
499 
500 static void
img_text_from_bottom(cairo_t * cr,PangoLayout * layout,gint sw,gint sh,gint lw,gint lh,gint posx,gint posy,gdouble progress,gdouble * font_color,gdouble * font_bgcolor)501 img_text_from_bottom( cairo_t     *cr,
502 					  PangoLayout *layout,
503 					  gint         sw,
504 					  gint         sh,
505   					  gint         lw,
506   					  gint         lh,
507   					  gint         posx,
508   					  gint         posy,
509   					  gdouble      progress,
510                       gdouble     *font_color,
511                       gdouble     *font_bgcolor)
512 {
513     img_text_draw_layout(cr, layout,
514                          posx,
515                          posy * progress + sh * ( 1 - progress ),
516                          font_color, font_bgcolor);
517 }
518 
519 static void
img_text_grow(cairo_t * cr,PangoLayout * layout,gint sw,gint sh,gint lw,gint lh,gint posx,gint posy,gdouble progress,gdouble * font_color,gdouble * font_bgcolor)520 img_text_grow( cairo_t     *cr,
521 			   PangoLayout *layout,
522 			   gint         sw,
523 			   gint         sh,
524 			   gint         lw,
525 			   gint         lh,
526 			   gint         posx,
527 			   gint         posy,
528 			   gdouble      progress,
529                gdouble     *font_color,
530                gdouble     *font_bgcolor)
531 {
532 	cairo_translate( cr, posx + lw * 0.5, posy + lh * 0.5 );
533 	cairo_scale( cr, progress, progress );
534 
535     img_text_draw_layout(cr, layout,
536                          - lw * 0.5,
537                          - lh * 0.5,
538                          font_color, font_bgcolor);
539 }
540 
541