Coverage Report

Created: 2026-08-31 08:22

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
214k
{
34
214k
    if( unlikely( term.psz == NULL ) )
35
647
        return;
36
37
213k
    if( term.type == TYPE_FUNCTION )
38
3.57k
    {
39
3.57k
        if( term.function ) /* func( expr ) */
40
3.36k
        {
41
3.36k
            if( ( !strcmp( term.psz, "rgb" ) && term.function->i_count == 3 ) ||
42
2.39k
                ( !strcmp( term.psz, "rgba" ) && term.function->i_count == 4 ) )
43
1.21k
            {
44
1.21k
                *color = (((uint32_t)term.function->seq[0].term.val) << 16) |
45
1.21k
                         (((uint32_t)term.function->seq[1].term.val) << 8) |
46
1.21k
                          ((uint32_t)term.function->seq[2].term.val);
47
1.21k
                *feat |= cflag;
48
1.21k
                if( term.psz[3] != 0 ) /* rgba */
49
247
                {
50
247
                    *alpha = term.function->seq[3].term.val * STYLE_ALPHA_OPAQUE;
51
247
                    *feat |= aflag;
52
247
                }
53
1.21k
            }
54
3.36k
        }
55
3.57k
    }
56
209k
    else if( term.type == TYPE_STRING ||
57
209k
             term.type == TYPE_HEXCOLOR ||
58
207k
             term.type == TYPE_IDENTIFIER )
59
209k
    {
60
209k
        bool b_valid = false;
61
209k
        unsigned i_color = vlc_html_color( term.psz, &b_valid );
62
209k
        if( b_valid )
63
201k
        {
64
201k
            *alpha = (i_color & 0xFF000000) >> 24;
65
201k
            *color = i_color & 0x00FFFFFF;
66
201k
            *feat |= cflag|aflag;
67
201k
        }
68
209k
    }
69
213k
}
70
71
static void OutlineWidth( vlc_css_term_t term, text_style_t *p_style )
72
2.48k
{
73
2.48k
    if( term.type >= TYPE_PIXELS )
74
1.90k
    {
75
1.90k
        p_style->i_outline_width = term.val;
76
1.90k
        p_style->i_style_flags |= STYLE_OUTLINE;
77
1.90k
        p_style->i_features |= STYLE_HAS_FLAGS;
78
1.90k
    }
79
2.48k
}
80
81
static void OutlineColor( vlc_css_term_t term, text_style_t *p_style )
82
1.19k
{
83
1.19k
    Color( term, &p_style->i_outline_color, &p_style->i_outline_alpha,
84
1.19k
           &p_style->i_features, STYLE_HAS_OUTLINE_COLOR, STYLE_HAS_OUTLINE_ALPHA );
85
1.19k
}
86
87
static void ShadowDrop( vlc_css_term_t term, text_style_t *p_style )
88
2.21k
{
89
2.21k
    if( term.type >= TYPE_PIXELS )
90
880
    {
91
880
        p_style->i_shadow_width = term.val;
92
880
        p_style->i_style_flags |= STYLE_SHADOW;
93
880
        p_style->i_features |= STYLE_HAS_FLAGS;
94
880
    }
95
2.21k
}
96
97
static void ShadowColor( vlc_css_term_t term, text_style_t *p_style )
98
1.69k
{
99
1.69k
    Color( term, &p_style->i_shadow_color, &p_style->i_shadow_alpha,
100
1.69k
           &p_style->i_features, STYLE_HAS_SHADOW_COLOR, STYLE_HAS_SHADOW_ALPHA );
101
1.69k
}
102
103
void webvtt_FillStyleFromCssDeclaration( const vlc_css_declaration_t *p_decl, text_style_t *p_style )
104
285k
{
105
285k
    if( !p_decl->psz_property || !p_style )
106
0
        return;
107
108
    /* Only support simple expressions for now */
109
285k
    if( !p_decl->expr || p_decl->expr->i_count < 1 )
110
0
        return;
111
112
285k
    vlc_css_term_t term0 = p_decl->expr->seq[0].term;
113
114
285k
    if( !strcasecmp( p_decl->psz_property, "color" ) )
115
210k
    {
116
210k
        Color( term0, &p_style->i_font_color, &p_style->i_font_alpha,
117
210k
               &p_style->i_features, STYLE_HAS_FONT_COLOR, STYLE_HAS_FONT_ALPHA );
118
210k
    }
119
75.0k
    else if( !strcasecmp( p_decl->psz_property, "text-decoration" ) )
120
31.5k
    {
121
31.5k
        if( term0.type == TYPE_STRING )
122
30.9k
        {
123
30.9k
            if( !strcasecmp( term0.psz, "none" ) )
124
250
            {
125
250
                p_style->i_style_flags &= ~(STYLE_STRIKEOUT|STYLE_UNDERLINE);
126
250
                p_style->i_features |= STYLE_HAS_FLAGS;
127
250
            }
128
30.7k
            else if( !strcasecmp( term0.psz, "line-through" ) )
129
367
            {
130
367
                p_style->i_style_flags |= STYLE_STRIKEOUT;
131
367
                p_style->i_features |= STYLE_HAS_FLAGS;
132
367
            }
133
30.3k
            else if( !strcasecmp( term0.psz, "underline" ) )
134
278
            {
135
278
                p_style->i_style_flags |= STYLE_UNDERLINE;
136
278
                p_style->i_features |= STYLE_HAS_FLAGS;
137
278
            }
138
30.9k
        }
139
31.5k
    }
140
43.5k
    else if( !strcasecmp( p_decl->psz_property, "text-shadow" ) )
141
2.21k
    {
142
2.21k
        ShadowDrop( term0, p_style );
143
2.21k
        if( p_decl->expr->i_count == 3 )
144
1.69k
            ShadowColor( p_decl->expr->seq[2].term, p_style );
145
2.21k
    }
146
41.3k
    else if( !strcasecmp( p_decl->psz_property, "background-color" ) )
147
366
    {
148
366
        Color( term0, &p_style->i_background_color, &p_style->i_background_alpha,
149
366
               &p_style->i_features, STYLE_HAS_BACKGROUND_COLOR, STYLE_HAS_BACKGROUND_ALPHA );
150
366
        p_style->i_style_flags |= STYLE_BACKGROUND;
151
366
        p_style->i_features |= STYLE_HAS_FLAGS;
152
366
    }
153
40.9k
    else if( !strcasecmp( p_decl->psz_property, "outline-color" ) )
154
206
    {
155
206
        OutlineColor( term0, p_style );
156
206
    }
157
40.7k
    else if( !strcasecmp( p_decl->psz_property, "outline-width" ) )
158
894
    {
159
894
        OutlineWidth( term0, p_style );
160
894
    }
161
39.8k
    else if( !strcasecmp( p_decl->psz_property, "outline" ) )
162
1.59k
    {
163
1.59k
        OutlineWidth( term0, p_style );
164
1.59k
        if( p_decl->expr->i_count == 3 )
165
991
            OutlineColor( p_decl->expr->seq[2].term, p_style );
166
1.59k
    }
167
38.2k
    else if( !strcasecmp( p_decl->psz_property, "font-family" ) )
168
1.88k
    {
169
1.88k
        const vlc_css_term_t *term;
170
1.88k
        if( term0.type >= TYPE_STRING )
171
1.65k
        {
172
1.65k
            size_t i_total = 1 + (p_decl->expr->i_count - 1) * 2;
173
28.7k
            for( size_t i=0; i<p_decl->expr->i_count; i++ )
174
27.0k
            {
175
27.0k
                term = &p_decl->expr->seq[i].term;
176
27.0k
                if( term->type < TYPE_STRING )
177
17.3k
                    continue;
178
9.70k
                i_total += strlen( term->psz );
179
9.70k
                if( term->type == TYPE_STRING )
180
3.20k
                    i_total += 2;
181
9.70k
            }
182
1.65k
            char *psz = malloc( i_total );
183
1.65k
            if( psz )
184
1.65k
            {
185
1.65k
                *psz = 0;
186
28.7k
                for( size_t i=0; i<p_decl->expr->i_count; i++ )
187
27.0k
                {
188
27.0k
                    term = &p_decl->expr->seq[i].term;
189
27.0k
                    if( term->type < TYPE_STRING )
190
17.3k
                        continue;
191
9.70k
                    if( i > 0 )
192
8.05k
                        strcat( psz, ", " );
193
9.70k
                    i_total += strlen( term->psz );
194
9.70k
                    if( term->type == TYPE_STRING )
195
3.20k
                        strcat( psz, "\"" );
196
9.70k
                    strcat( psz, term->psz );
197
9.70k
                    if( term->type == TYPE_STRING )
198
3.20k
                        strcat( psz, "\"" );
199
9.70k
                }
200
1.65k
                free( p_style->psz_fontname );
201
1.65k
                p_style->psz_fontname = psz;
202
1.65k
            }
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.65k
        }
213
1.88k
    }
214
36.3k
    else if( !strcasecmp( p_decl->psz_property, "font-style" ) )
215
925
    {
216
925
        if( term0.type >= TYPE_STRING )
217
696
        {
218
696
            if( !strcasecmp(term0.psz, "normal") )
219
200
            {
220
200
                p_style->i_style_flags &= ~STYLE_ITALIC;
221
200
                p_style->i_features |= STYLE_HAS_FLAGS;
222
200
            }
223
496
            else if( !strcasecmp(term0.psz, "italic") )
224
51
            {
225
51
                p_style->i_style_flags |= STYLE_ITALIC;
226
51
                p_style->i_features |= STYLE_HAS_FLAGS;
227
51
            }
228
696
        }
229
925
    }
230
35.4k
    else if( !strcasecmp( p_decl->psz_property, "font-weight" ) )
231
1.97k
    {
232
1.97k
        if( term0.type >= TYPE_STRING )
233
1.32k
        {
234
1.32k
            if( !strcasecmp(term0.psz, "normal") )
235
281
            {
236
281
                p_style->i_style_flags &= ~STYLE_BOLD;
237
281
                p_style->i_features |= STYLE_HAS_FLAGS;
238
281
            }
239
1.32k
            if( !strcasecmp(term0.psz, "bold") )
240
233
            {
241
233
                p_style->i_style_flags |= STYLE_BOLD;
242
233
                p_style->i_features |= STYLE_HAS_FLAGS;
243
233
            }
244
1.32k
        }
245
644
        else if( term0.type == TYPE_NONE )
246
439
        {
247
439
            if( term0.val >= 700.0 )
248
201
                p_style->i_style_flags |= STYLE_BOLD;
249
238
            else
250
238
                p_style->i_style_flags &= ~STYLE_BOLD;
251
439
            p_style->i_features |= STYLE_HAS_FLAGS;
252
439
        }
253
1.97k
    }
254
33.4k
    else if( !strcasecmp( p_decl->psz_property, "font-size" ) )
255
2.07k
    {
256
2.07k
        if( term0.type == TYPE_PIXELS )
257
533
            p_style->i_font_size = term0.val;
258
1.54k
        else if( term0.type == TYPE_EMS )
259
330
            p_style->f_font_relsize = term0.val * 5.33 / 1.06;
260
1.21k
        else if( term0.type == TYPE_PERCENT )
261
320
            p_style->f_font_relsize = term0.val * 5.33 / 100;
262
2.07k
    }
263
31.4k
    else if( !strcasecmp( p_decl->psz_property, "font" ) )
264
404
    {
265
        /* what to do ? */
266
404
    }
267
30.9k
    else if( !strcasecmp( p_decl->psz_property, "white-space" ) )
268
2.11k
    {
269
2.11k
        if( term0.type >= TYPE_STRING )
270
1.70k
        {
271
1.70k
            if( !strcasecmp(term0.psz, "normal" ) )
272
82
                p_style->e_wrapinfo = STYLE_WRAP_DEFAULT;
273
1.70k
            if( !strcasecmp(term0.psz, "nowrap" ) )
274
298
                p_style->e_wrapinfo = STYLE_WRAP_NONE;
275
1.70k
        }
276
2.11k
    }
277
285k
}