sout: sdi: fix channels to pairs setup
[vlc.git] / src / misc / text_style.c
blob0695f94d89d9993994f1822467dd085d3a7b3db9
1 /*****************************************************************************
2 * text_style.c
3 *****************************************************************************
4 * Copyright (C) 1999-2010 VLC authors and VideoLAN
5 * $Id$
7 * Author: basOS G <noxelia 4t gmail , com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <vlc_common.h>
29 #include <vlc_text_style.h>
31 #include <ctype.h>
33 /* */
34 text_style_t *text_style_New( void )
36 return text_style_Create( STYLE_FULLY_SET );
39 text_style_t *text_style_Create( int i_defaults )
41 text_style_t *p_style = calloc( 1, sizeof(*p_style) );
42 if( !p_style )
43 return NULL;
45 if( i_defaults == STYLE_NO_DEFAULTS )
46 return p_style;
48 /* initialize to default text style (FIXME: by flag) */
49 p_style->psz_fontname = NULL;
50 p_style->psz_monofontname = NULL;
51 p_style->i_features = STYLE_FULLY_SET;
52 p_style->i_style_flags = STYLE_OUTLINE;
53 p_style->f_font_relsize = STYLE_DEFAULT_REL_FONT_SIZE;
54 p_style->i_font_size = STYLE_DEFAULT_FONT_SIZE;
55 p_style->i_font_color = 0xffffff;
56 p_style->i_font_alpha = STYLE_ALPHA_OPAQUE;
57 p_style->i_outline_color = 0x000000;
58 p_style->i_outline_alpha = STYLE_ALPHA_OPAQUE;
59 p_style->i_shadow_color = 0x808080;
60 p_style->i_shadow_alpha = STYLE_ALPHA_OPAQUE;
61 p_style->i_background_color = 0x000000;
62 p_style->i_background_alpha = STYLE_ALPHA_OPAQUE;
63 p_style->i_karaoke_background_color = 0xffffff;
64 p_style->i_karaoke_background_alpha = STYLE_ALPHA_OPAQUE;
65 p_style->i_outline_width = 1;
66 p_style->i_shadow_width = 0;
67 p_style->i_spacing = -1;
68 p_style->e_wrapinfo = STYLE_WRAP_DEFAULT;
70 return p_style;
73 text_style_t *text_style_Copy( text_style_t *p_dst, const text_style_t *p_src )
75 if( !p_src )
76 return p_dst;
78 /* */
79 *p_dst = *p_src;
81 if( p_src->psz_fontname )
82 p_dst->psz_fontname = strdup( p_src->psz_fontname );
84 if( p_src->psz_monofontname )
85 p_dst->psz_monofontname = strdup( p_src->psz_monofontname );
87 return p_dst;
90 #define MERGE(var, fflag) \
91 if( (p_src->i_features & fflag) && (b_override || !(p_dst->i_features & fflag)) )\
92 p_dst->var = p_src->var
94 #define MERGE_SIZE(var) \
95 if( p_src->var > 0 && (b_override || p_dst->var <= 0) )\
96 p_dst->var = p_src->var
98 void text_style_Merge( text_style_t *p_dst, const text_style_t *p_src, bool b_override )
100 if( p_src->psz_fontname && (!p_dst->psz_fontname || b_override) )
102 free( p_dst->psz_fontname );
103 p_dst->psz_fontname = strdup( p_src->psz_fontname );
106 if( p_src->psz_monofontname && (!p_dst->psz_monofontname || b_override) )
108 free( p_dst->psz_monofontname );
109 p_dst->psz_monofontname = strdup( p_src->psz_monofontname );
112 if( p_src->i_features != STYLE_NO_DEFAULTS )
114 MERGE(i_font_color, STYLE_HAS_FONT_COLOR);
115 MERGE(i_font_alpha, STYLE_HAS_FONT_ALPHA);
116 MERGE(i_outline_color, STYLE_HAS_OUTLINE_COLOR);
117 MERGE(i_outline_alpha, STYLE_HAS_OUTLINE_ALPHA);
118 MERGE(i_shadow_color, STYLE_HAS_SHADOW_COLOR);
119 MERGE(i_shadow_alpha, STYLE_HAS_SHADOW_ALPHA);
120 MERGE(i_background_color, STYLE_HAS_BACKGROUND_COLOR);
121 MERGE(i_background_alpha, STYLE_HAS_BACKGROUND_ALPHA);
122 MERGE(i_karaoke_background_color, STYLE_HAS_K_BACKGROUND_COLOR);
123 MERGE(i_karaoke_background_alpha, STYLE_HAS_K_BACKGROUND_ALPHA);
124 MERGE(e_wrapinfo, STYLE_HAS_WRAP_INFO);
125 p_dst->i_features |= p_src->i_features;
126 p_dst->i_style_flags |= p_src->i_style_flags;
129 MERGE_SIZE(f_font_relsize);
130 MERGE_SIZE(i_font_size);
131 MERGE_SIZE(i_outline_width);
132 MERGE_SIZE(i_shadow_width);
133 MERGE_SIZE(i_spacing);
136 #undef MERGE
137 #undef MERGE_SIZE
139 text_style_t *text_style_Duplicate( const text_style_t *p_src )
141 if( !p_src )
142 return NULL;
144 text_style_t *p_dst = calloc( 1, sizeof(*p_dst) );
145 if( p_dst )
146 text_style_Copy( p_dst, p_src );
147 return p_dst;
150 void text_style_Delete( text_style_t *p_style )
152 if( p_style )
153 free( p_style->psz_fontname );
154 if( p_style )
155 free( p_style->psz_monofontname );
156 free( p_style );
159 void text_segment_ruby_ChainDelete( text_segment_ruby_t *p_ruby )
161 while( p_ruby )
163 text_segment_ruby_t *p_next = p_ruby->p_next;
164 free( p_ruby->psz_base );
165 free( p_ruby->psz_rt );
166 free( p_ruby );
167 p_ruby = p_next;
171 text_segment_ruby_t *text_segment_ruby_New( const char *psz_base,
172 const char *psz_rt )
174 text_segment_ruby_t *p_rb = malloc(sizeof(*p_rb));
175 if( p_rb )
177 p_rb->p_next = NULL;
178 p_rb->psz_base = strdup( psz_base );
179 p_rb->psz_rt = strdup( psz_rt );
180 if( !p_rb->psz_base || !p_rb->psz_rt )
182 text_segment_ruby_ChainDelete( p_rb );
183 return NULL;
186 return p_rb;
189 static text_segment_ruby_t *text_segment_ruby_Duplicate( const text_segment_ruby_t *p_src )
191 text_segment_ruby_t *p_dup = NULL;
192 text_segment_ruby_t **pp_append = &p_dup;
193 for ( ; p_src ; p_src = p_src->p_next )
195 *pp_append = text_segment_ruby_New( p_src->psz_base, p_src->psz_rt );
196 if( *pp_append )
197 pp_append = &((*pp_append)->p_next);
199 return p_dup;
202 text_segment_t *text_segment_New( const char *psz_text )
204 text_segment_t* segment = calloc( 1, sizeof(*segment) );
205 if( !segment )
206 return NULL;
208 if ( psz_text )
209 segment->psz_text = strdup( psz_text );
211 return segment;
214 text_segment_t *text_segment_NewInheritStyle( const text_style_t* p_style )
216 if ( !p_style )
217 return NULL; //FIXME: Allow this, even if it is an alias to text_segment_New( NULL ) ?
218 text_segment_t* p_segment = text_segment_New( NULL );
219 if ( unlikely( !p_segment ) )
220 return NULL;
221 p_segment->style = text_style_Duplicate( p_style );
222 if ( unlikely( !p_segment->style ) )
224 text_segment_Delete( p_segment );
225 return NULL;
227 return p_segment;
230 text_segment_t *text_segment_FromRuby( text_segment_ruby_t *p_ruby )
232 text_segment_t *p_segment = text_segment_New( NULL );
233 if( p_segment )
235 p_segment->p_ruby = p_ruby;
236 size_t i_base = 1;
237 for( text_segment_ruby_t *p = p_ruby; p; p = p->p_next )
238 i_base += strlen( p->psz_base );
239 p_segment->psz_text = malloc( i_base );
240 /* Fallback for those not understanding p_ruby */
241 if( p_segment->psz_text )
243 *p_segment->psz_text = 0;
244 for( text_segment_ruby_t *p = p_ruby; p; p = p->p_next )
245 strcat( p_segment->psz_text, p->psz_base );
248 return p_segment;
251 void text_segment_Delete( text_segment_t* segment )
253 if ( segment != NULL )
255 free( segment->psz_text );
256 text_style_Delete( segment->style );
257 text_segment_ruby_ChainDelete( segment->p_ruby );
258 free( segment );
262 void text_segment_ChainDelete( text_segment_t *segment )
264 while( segment != NULL )
266 text_segment_t *p_next = segment->p_next;
268 text_segment_Delete( segment );
270 segment = p_next;
274 text_segment_t *text_segment_Copy( text_segment_t *p_src )
276 text_segment_t *p_dst = NULL, *p_dst0 = NULL;
278 while( p_src ) {
279 text_segment_t *p_new = text_segment_New( p_src->psz_text );
281 if( unlikely( !p_new ) )
282 break;
284 p_new->style = text_style_Duplicate( p_src->style );
285 p_new->p_ruby = text_segment_ruby_Duplicate( p_src->p_ruby );
287 if( p_dst == NULL )
289 p_dst = p_dst0 = p_new;
291 else
293 p_dst->p_next = p_new;
294 p_dst = p_dst->p_next;
297 p_src = p_src->p_next;
300 return p_dst0;
303 unsigned int vlc_html_color( const char *psz_value, bool* ok )
305 unsigned int color = 0;
306 char* psz_end;
307 bool b_ret = false;
309 const char *psz_hex = (*psz_value == '#') ? psz_value + 1 : psz_value;
311 if( psz_hex != psz_value ||
312 (*psz_hex >= '0' && *psz_hex <= '9') ||
313 (*psz_hex >= 'A' && *psz_hex <= 'F') )
315 uint32_t i_value = (uint32_t)strtoul( psz_hex, &psz_end, 16 );
316 if( *psz_end == 0 || isspace( *psz_end ) )
318 switch( psz_end - psz_hex )
320 case 8:
321 color = (i_value << 24) | (i_value >> 8);
322 b_ret = true;
323 break;
324 case 6:
325 color = i_value | 0xFF000000;
326 b_ret = true;
327 break;
328 default:
329 break;
334 if( !b_ret && psz_hex == psz_value &&
335 !strncmp( "rgb", psz_value, 3 ) )
337 unsigned r,g,b,a = 0xFF;
338 if( psz_value[3] == 'a' )
339 b_ret = (sscanf( psz_value, "rgba(%3u,%3u,%3u,%3u)", &r, &g, &b, &a ) == 4);
340 else
341 b_ret = (sscanf( psz_value, "rgb(%3u,%3u,%3u)", &r, &g, &b ) == 3);
342 color = (a << 24) | (r << 16) | (g << 8) | b;
345 if( !b_ret && psz_hex == psz_value )
347 for( int i = 0; p_html_colors[i].psz_name != NULL; i++ )
349 if( !strcasecmp( psz_value, p_html_colors[i].psz_name ) )
351 // Assume opaque color since the table doesn't specify an alpha
352 color = p_html_colors[i].i_value | 0xFF000000;
353 b_ret = true;
354 break;
359 if ( ok != NULL )
360 *ok = b_ret;
362 return color;