Coverage Report

Created: 2026-04-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/codec/webvtt/css_style.c
Line
Count
Source
1
/*****************************************************************************
2
 * css_style.c : CSS styles conversions
3
 *****************************************************************************
4
 * Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published by
8
 * the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19
 *****************************************************************************/
20
#ifdef HAVE_CONFIG_H
21
# include "config.h"
22
#endif
23
24
#include <vlc_common.h>
25
#include <vlc_text_style.h>
26
27
#include "css_parser.h"
28
#include "css_style.h"
29
30
static void Color( vlc_css_term_t term,
31
                   uint32_t *color, uint8_t *alpha,
32
                   uint16_t *feat, int cflag, int aflag )
33
14.8k
{
34
14.8k
    if( unlikely( term.psz == NULL ) )
35
397
        return;
36
37
14.4k
    if( term.type == TYPE_FUNCTION )
38
2.95k
    {
39
2.95k
        if( term.function ) /* func( expr ) */
40
2.55k
        {
41
2.55k
            if( ( !strcmp( term.psz, "rgb" ) && term.function->i_count == 3 ) ||
42
1.61k
                ( !strcmp( term.psz, "rgba" ) && term.function->i_count == 4 ) )
43
1.14k
            {
44
1.14k
                *color = (((uint32_t)term.function->seq[0].term.val) << 16) |
45
1.14k
                         (((uint32_t)term.function->seq[1].term.val) << 8) |
46
1.14k
                          ((uint32_t)term.function->seq[2].term.val);
47
1.14k
                *feat |= cflag;
48
1.14k
                if( term.psz[3] != 0 ) /* rgba */
49
209
                {
50
209
                    *alpha = term.function->seq[3].term.val * STYLE_ALPHA_OPAQUE;
51
209
                    *feat |= aflag;
52
209
                }
53
1.14k
            }
54
2.55k
        }
55
2.95k
    }
56
11.5k
    else if( term.type == TYPE_STRING ||
57
11.3k
             term.type == TYPE_HEXCOLOR ||
58
9.94k
             term.type == TYPE_IDENTIFIER )
59
11.2k
    {
60
11.2k
        bool b_valid = false;
61
11.2k
        unsigned i_color = vlc_html_color( term.psz, &b_valid );
62
11.2k
        if( b_valid )
63
7.42k
        {
64
7.42k
            *alpha = (i_color & 0xFF000000) >> 24;
65
7.42k
            *color = i_color & 0x00FFFFFF;
66
7.42k
            *feat |= cflag|aflag;
67
7.42k
        }
68
11.2k
    }
69
14.4k
}
70
71
static void OutlineWidth( vlc_css_term_t term, text_style_t *p_style )
72
1.46k
{
73
1.46k
    if( term.type >= TYPE_PIXELS )
74
1.01k
    {
75
1.01k
        p_style->i_outline_width = term.val;
76
1.01k
        p_style->i_style_flags |= STYLE_OUTLINE;
77
1.01k
        p_style->i_features |= STYLE_HAS_FLAGS;
78
1.01k
    }
79
1.46k
}
80
81
static void OutlineColor( vlc_css_term_t term, text_style_t *p_style )
82
443
{
83
443
    Color( term, &p_style->i_outline_color, &p_style->i_outline_alpha,
84
443
           &p_style->i_features, STYLE_HAS_OUTLINE_COLOR, STYLE_HAS_OUTLINE_ALPHA );
85
443
}
86
87
static void ShadowDrop( vlc_css_term_t term, text_style_t *p_style )
88
1.12k
{
89
1.12k
    if( term.type >= TYPE_PIXELS )
90
996
    {
91
996
        p_style->i_shadow_width = term.val;
92
996
        p_style->i_style_flags |= STYLE_SHADOW;
93
996
        p_style->i_features |= STYLE_HAS_FLAGS;
94
996
    }
95
1.12k
}
96
97
static void ShadowColor( vlc_css_term_t term, text_style_t *p_style )
98
918
{
99
918
    Color( term, &p_style->i_shadow_color, &p_style->i_shadow_alpha,
100
918
           &p_style->i_features, STYLE_HAS_SHADOW_COLOR, STYLE_HAS_SHADOW_ALPHA );
101
918
}
102
103
void webvtt_FillStyleFromCssDeclaration( const vlc_css_declaration_t *p_decl, text_style_t *p_style )
104
40.1k
{
105
40.1k
    if( !p_decl->psz_property || !p_style )
106
0
        return;
107
108
    /* Only support simple expressions for now */
109
40.1k
    if( !p_decl->expr || p_decl->expr->i_count < 1 )
110
0
        return;
111
112
40.1k
    vlc_css_term_t term0 = p_decl->expr->seq[0].term;
113
114
40.1k
    if( !strcasecmp( p_decl->psz_property, "color" ) )
115
13.0k
    {
116
13.0k
        Color( term0, &p_style->i_font_color, &p_style->i_font_alpha,
117
13.0k
               &p_style->i_features, STYLE_HAS_FONT_COLOR, STYLE_HAS_FONT_ALPHA );
118
13.0k
    }
119
27.1k
    else if( !strcasecmp( p_decl->psz_property, "text-decoration" ) )
120
4.93k
    {
121
4.93k
        if( term0.type == TYPE_STRING )
122
4.73k
        {
123
4.73k
            if( !strcasecmp( term0.psz, "none" ) )
124
98
            {
125
98
                p_style->i_style_flags &= ~(STYLE_STRIKEOUT|STYLE_UNDERLINE);
126
98
                p_style->i_features |= STYLE_HAS_FLAGS;
127
98
            }
128
4.63k
            else if( !strcasecmp( term0.psz, "line-through" ) )
129
294
            {
130
294
                p_style->i_style_flags |= STYLE_STRIKEOUT;
131
294
                p_style->i_features |= STYLE_HAS_FLAGS;
132
294
            }
133
4.34k
            else if( !strcasecmp( term0.psz, "underline" ) )
134
228
            {
135
228
                p_style->i_style_flags |= STYLE_UNDERLINE;
136
228
                p_style->i_features |= STYLE_HAS_FLAGS;
137
228
            }
138
4.73k
        }
139
4.93k
    }
140
22.2k
    else if( !strcasecmp( p_decl->psz_property, "text-shadow" ) )
141
1.12k
    {
142
1.12k
        ShadowDrop( term0, p_style );
143
1.12k
        if( p_decl->expr->i_count == 3 )
144
918
            ShadowColor( p_decl->expr->seq[2].term, p_style );
145
1.12k
    }
146
21.0k
    else if( !strcasecmp( p_decl->psz_property, "background-color" ) )
147
490
    {
148
490
        Color( term0, &p_style->i_background_color, &p_style->i_background_alpha,
149
490
               &p_style->i_features, STYLE_HAS_BACKGROUND_COLOR, STYLE_HAS_BACKGROUND_ALPHA );
150
490
        p_style->i_style_flags |= STYLE_BACKGROUND;
151
490
        p_style->i_features |= STYLE_HAS_FLAGS;
152
490
    }
153
20.5k
    else if( !strcasecmp( p_decl->psz_property, "outline-color" ) )
154
187
    {
155
187
        OutlineColor( term0, p_style );
156
187
    }
157
20.3k
    else if( !strcasecmp( p_decl->psz_property, "outline-width" ) )
158
822
    {
159
822
        OutlineWidth( term0, p_style );
160
822
    }
161
19.5k
    else if( !strcasecmp( p_decl->psz_property, "outline" ) )
162
644
    {
163
644
        OutlineWidth( term0, p_style );
164
644
        if( p_decl->expr->i_count == 3 )
165
256
            OutlineColor( p_decl->expr->seq[2].term, p_style );
166
644
    }
167
18.9k
    else if( !strcasecmp( p_decl->psz_property, "font-family" ) )
168
1.38k
    {
169
1.38k
        vlc_css_term_t *term;
170
1.38k
        if( term0.type >= TYPE_STRING )
171
1.17k
        {
172
1.17k
            size_t i_total = 1 + (p_decl->expr->i_count - 1) * 2;
173
20.5k
            for( size_t i=0; i<p_decl->expr->i_count; i++ )
174
19.3k
            {
175
19.3k
                term = &p_decl->expr->seq[i].term;
176
19.3k
                if( term->type < TYPE_STRING )
177
15.5k
                    continue;
178
3.78k
                i_total += strlen( term->psz );
179
3.78k
                if( term->type == TYPE_STRING )
180
1.67k
                    i_total += 2;
181
3.78k
            }
182
1.17k
            char *psz = malloc( i_total );
183
1.17k
            if( psz )
184
1.17k
            {
185
1.17k
                *psz = 0;
186
20.5k
                for( size_t i=0; i<p_decl->expr->i_count; i++ )
187
19.3k
                {
188
19.3k
                    term = &p_decl->expr->seq[i].term;
189
19.3k
                    if( term->type < TYPE_STRING )
190
15.5k
                        continue;
191
3.78k
                    if( i > 0 )
192
2.60k
                        strcat( psz, ", " );
193
3.78k
                    i_total += strlen( term->psz );
194
3.78k
                    if( term->type == TYPE_STRING )
195
1.67k
                        strcat( psz, "\"" );
196
3.78k
                    strcat( psz, term->psz );
197
3.78k
                    if( term->type == TYPE_STRING )
198
1.67k
                        strcat( psz, "\"" );
199
3.78k
                }
200
1.17k
                free( p_style->psz_fontname );
201
1.17k
                p_style->psz_fontname = psz;
202
1.17k
            }
203
            /*char *psz_font = NULL;
204
            const char *psz = strchr( term0.psz, ',' );
205
            if( psz )
206
                psz_font = strndup( term0.psz, psz - term0.psz + 1 );
207
            else
208
                psz_font = strdup( term0.psz );
209
            free( p_style->psz_fontname );
210
            p_style->psz_fontname = vlc_css_unquoted( psz_font );
211
            free( psz_font );*/
212
1.17k
        }
213
1.38k
    }
214
17.5k
    else if( !strcasecmp( p_decl->psz_property, "font-style" ) )
215
881
    {
216
881
        if( term0.type >= TYPE_STRING )
217
814
        {
218
814
            if( !strcasecmp(term0.psz, "normal") )
219
184
            {
220
184
                p_style->i_style_flags &= ~STYLE_ITALIC;
221
184
                p_style->i_features |= STYLE_HAS_FLAGS;
222
184
            }
223
630
            else if( !strcasecmp(term0.psz, "italic") )
224
200
            {
225
200
                p_style->i_style_flags |= STYLE_ITALIC;
226
200
                p_style->i_features |= STYLE_HAS_FLAGS;
227
200
            }
228
814
        }
229
881
    }
230
16.6k
    else if( !strcasecmp( p_decl->psz_property, "font-weight" ) )
231
1.64k
    {
232
1.64k
        if( term0.type >= TYPE_STRING )
233
1.01k
        {
234
1.01k
            if( !strcasecmp(term0.psz, "normal") )
235
217
            {
236
217
                p_style->i_style_flags &= ~STYLE_BOLD;
237
217
                p_style->i_features |= STYLE_HAS_FLAGS;
238
217
            }
239
1.01k
            if( !strcasecmp(term0.psz, "bold") )
240
146
            {
241
146
                p_style->i_style_flags |= STYLE_BOLD;
242
146
                p_style->i_features |= STYLE_HAS_FLAGS;
243
146
            }
244
1.01k
        }
245
627
        else if( term0.type == TYPE_NONE )
246
432
        {
247
432
            if( term0.val >= 700.0 )
248
207
                p_style->i_style_flags |= STYLE_BOLD;
249
225
            else
250
225
                p_style->i_style_flags &= ~STYLE_BOLD;
251
432
            p_style->i_features |= STYLE_HAS_FLAGS;
252
432
        }
253
1.64k
    }
254
15.0k
    else if( !strcasecmp( p_decl->psz_property, "font-size" ) )
255
1.46k
    {
256
1.46k
        if( term0.type == TYPE_PIXELS )
257
373
            p_style->i_font_size = term0.val;
258
1.08k
        else if( term0.type == TYPE_EMS )
259
0
            p_style->f_font_relsize = term0.val * 5.33 / 1.06;
260
1.08k
        else if( term0.type == TYPE_PERCENT )
261
321
            p_style->f_font_relsize = term0.val * 5.33 / 100;
262
1.46k
    }
263
13.5k
    else if( !strcasecmp( p_decl->psz_property, "font" ) )
264
2.39k
    {
265
        /* what to do ? */
266
2.39k
    }
267
11.1k
    else if( !strcasecmp( p_decl->psz_property, "white-space" ) )
268
1.01k
    {
269
1.01k
        if( term0.type >= TYPE_STRING )
270
830
        {
271
830
            if( !strcasecmp(term0.psz, "normal" ) )
272
414
                p_style->e_wrapinfo = STYLE_WRAP_DEFAULT;
273
830
            if( !strcasecmp(term0.psz, "nowrap" ) )
274
69
                p_style->e_wrapinfo = STYLE_WRAP_NONE;
275
830
        }
276
1.01k
    }
277
40.1k
}