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