1 /*****************************************************************************
2 * text_style.c
3 *****************************************************************************
4 * Copyright (C) 1999-2010 VLC authors and VideoLAN
5 * $Id: 90de47a912415dec4c6620296f3379de10904531 $
6 *
7 * Author: basOS G <noxelia 4t gmail , com>
8 *
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.
13 *
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.
18 *
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 *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <vlc_common.h>
29 #include <vlc_text_style.h>
30
31 #include <ctype.h>
32
33 /* */
text_style_New(void)34 text_style_t *text_style_New( void )
35 {
36 return text_style_Create( STYLE_FULLY_SET );
37 }
38
text_style_Create(int i_defaults)39 text_style_t *text_style_Create( int i_defaults )
40 {
41 text_style_t *p_style = calloc( 1, sizeof(*p_style) );
42 if( !p_style )
43 return NULL;
44
45 if( i_defaults == STYLE_NO_DEFAULTS )
46 return p_style;
47
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;
69
70 return p_style;
71 }
72
text_style_Copy(text_style_t * p_dst,const text_style_t * p_src)73 text_style_t *text_style_Copy( text_style_t *p_dst, const text_style_t *p_src )
74 {
75 if( !p_src )
76 return p_dst;
77
78 /* */
79 *p_dst = *p_src;
80
81 if( p_src->psz_fontname )
82 p_dst->psz_fontname = strdup( p_src->psz_fontname );
83
84 if( p_src->psz_monofontname )
85 p_dst->psz_monofontname = strdup( p_src->psz_monofontname );
86
87 return p_dst;
88 }
89
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
93
94 #define MERGE_SIZE(var) \
95 if( p_src->var > 0 && (b_override || p_dst->var <= 0) )\
96 p_dst->var = p_src->var
97
text_style_Merge(text_style_t * p_dst,const text_style_t * p_src,bool b_override)98 void text_style_Merge( text_style_t *p_dst, const text_style_t *p_src, bool b_override )
99 {
100 if( p_src->psz_fontname && (!p_dst->psz_fontname || b_override) )
101 {
102 free( p_dst->psz_fontname );
103 p_dst->psz_fontname = strdup( p_src->psz_fontname );
104 }
105
106 if( p_src->psz_monofontname && (!p_dst->psz_monofontname || b_override) )
107 {
108 free( p_dst->psz_monofontname );
109 p_dst->psz_monofontname = strdup( p_src->psz_monofontname );
110 }
111
112 if( p_src->i_features != STYLE_NO_DEFAULTS )
113 {
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;
127 }
128
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);
134 }
135
136 #undef MERGE
137 #undef MERGE_SIZE
138
text_style_Duplicate(const text_style_t * p_src)139 text_style_t *text_style_Duplicate( const text_style_t *p_src )
140 {
141 if( !p_src )
142 return NULL;
143
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;
148 }
149
text_style_Delete(text_style_t * p_style)150 void text_style_Delete( text_style_t *p_style )
151 {
152 if( p_style )
153 free( p_style->psz_fontname );
154 if( p_style )
155 free( p_style->psz_monofontname );
156 free( p_style );
157 }
158
text_segment_New(const char * psz_text)159 text_segment_t *text_segment_New( const char *psz_text )
160 {
161 text_segment_t* segment = calloc( 1, sizeof(*segment) );
162 if( !segment )
163 return NULL;
164
165 if ( psz_text )
166 segment->psz_text = strdup( psz_text );
167
168 return segment;
169 }
170
text_segment_NewInheritStyle(const text_style_t * p_style)171 text_segment_t *text_segment_NewInheritStyle( const text_style_t* p_style )
172 {
173 if ( !p_style )
174 return NULL; //FIXME: Allow this, even if it is an alias to text_segment_New( NULL ) ?
175 text_segment_t* p_segment = text_segment_New( NULL );
176 if ( unlikely( !p_segment ) )
177 return NULL;
178 p_segment->style = text_style_Duplicate( p_style );
179 if ( unlikely( !p_segment->style ) )
180 {
181 text_segment_Delete( p_segment );
182 return NULL;
183 }
184 return p_segment;
185 }
186
text_segment_Delete(text_segment_t * segment)187 void text_segment_Delete( text_segment_t* segment )
188 {
189 if ( segment != NULL )
190 {
191 free( segment->psz_text );
192 text_style_Delete( segment->style );
193 free( segment );
194 }
195 }
196
text_segment_ChainDelete(text_segment_t * segment)197 void text_segment_ChainDelete( text_segment_t *segment )
198 {
199 while( segment != NULL )
200 {
201 text_segment_t *p_next = segment->p_next;
202
203 text_segment_Delete( segment );
204
205 segment = p_next;
206 }
207 }
208
text_segment_Copy(text_segment_t * p_src)209 text_segment_t *text_segment_Copy( text_segment_t *p_src )
210 {
211 text_segment_t *p_dst = NULL, *p_dst0 = NULL;
212
213 while( p_src ) {
214 text_segment_t *p_new = text_segment_New( p_src->psz_text );
215
216 if( unlikely( !p_new ) )
217 break;
218
219 p_new->style = text_style_Duplicate( p_src->style );
220
221 if( p_dst == NULL )
222 {
223 p_dst = p_dst0 = p_new;
224 }
225 else
226 {
227 p_dst->p_next = p_new;
228 p_dst = p_dst->p_next;
229 }
230
231 p_src = p_src->p_next;
232 }
233
234 return p_dst0;
235 }
236
vlc_html_color(const char * psz_value,bool * ok)237 unsigned int vlc_html_color( const char *psz_value, bool* ok )
238 {
239 unsigned int color = 0;
240 char* psz_end;
241 bool b_ret = false;
242
243 const char *psz_hex = (*psz_value == '#') ? psz_value + 1 : psz_value;
244
245 if( psz_hex != psz_value ||
246 (*psz_hex >= '0' && *psz_hex <= '9') ||
247 (*psz_hex >= 'A' && *psz_hex <= 'F') )
248 {
249 uint32_t i_value = strtol( psz_hex, &psz_end, 16 );
250 if( *psz_end == 0 || isspace( *psz_end ) )
251 {
252 switch( psz_end - psz_hex )
253 {
254 case 8:
255 color = (i_value << 24) | (i_value >> 8);
256 b_ret = true;
257 break;
258 case 6:
259 color = i_value | 0xFF000000;
260 b_ret = true;
261 break;
262 default:
263 break;
264 }
265 }
266 }
267
268 if( !b_ret && psz_hex == psz_value &&
269 !strncmp( "rgb", psz_value, 3 ) )
270 {
271 unsigned r,g,b,a = 0xFF;
272 if( psz_value[3] == 'a' )
273 b_ret = (sscanf( psz_value, "rgba(%3u,%3u,%3u,%3u)", &r, &g, &b, &a ) == 4);
274 else
275 b_ret = (sscanf( psz_value, "rgb(%3u,%3u,%3u)", &r, &g, &b ) == 3);
276 color = (a << 24) | (r << 16) | (g << 8) | b;
277 }
278
279 if( !b_ret && psz_hex == psz_value )
280 {
281 for( int i = 0; p_html_colors[i].psz_name != NULL; i++ )
282 {
283 if( !strcasecmp( psz_value, p_html_colors[i].psz_name ) )
284 {
285 // Assume opaque color since the table doesn't specify an alpha
286 color = p_html_colors[i].i_value | 0xFF000000;
287 b_ret = true;
288 break;
289 }
290 }
291 }
292
293 if ( ok != NULL )
294 *ok = b_ret;
295
296 return color;
297 }
298