Coverage Report

Created: 2025-11-24 06:20

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
22.2k
{
34
22.2k
    if( unlikely( term.psz == NULL ) )
35
814
        return;
36
37
21.4k
    if( term.type == TYPE_FUNCTION )
38
6.19k
    {
39
6.19k
        if( term.function ) /* func( expr ) */
40
4.35k
        {
41
4.35k
            if( ( !strcmp( term.psz, "rgb" ) && term.function->i_count == 3 ) ||
42
2.46k
                ( !strcmp( term.psz, "rgba" ) && term.function->i_count == 4 ) )
43
2.16k
            {
44
2.16k
                *color = (((uint32_t)term.function->seq[0].term.val) << 16) |
45
2.16k
                         (((uint32_t)term.function->seq[1].term.val) << 8) |
46
2.16k
                          ((uint32_t)term.function->seq[2].term.val);
47
2.16k
                *feat |= cflag;
48
2.16k
                if( term.psz[3] != 0 ) /* rgba */
49
273
                {
50
273
                    *alpha = term.function->seq[3].term.val * STYLE_ALPHA_OPAQUE;
51
273
                    *feat |= aflag;
52
273
                }
53
2.16k
            }
54
4.35k
        }
55
6.19k
    }
56
15.2k
    else if( term.type == TYPE_STRING ||
57
14.9k
             term.type == TYPE_HEXCOLOR ||
58
8.18k
             term.type == TYPE_IDENTIFIER )
59
14.9k
    {
60
14.9k
        bool b_valid = false;
61
14.9k
        unsigned i_color = vlc_html_color( term.psz, &b_valid );
62
14.9k
        if( b_valid )
63
3.96k
        {
64
3.96k
            *alpha = (i_color & 0xFF000000) >> 24;
65
3.96k
            *color = i_color & 0x00FFFFFF;
66
3.96k
            *feat |= cflag|aflag;
67
3.96k
        }
68
14.9k
    }
69
21.4k
}
70
71
static void OutlineWidth( vlc_css_term_t term, text_style_t *p_style )
72
1.70k
{
73
1.70k
    if( term.type >= TYPE_PIXELS )
74
1.23k
    {
75
1.23k
        p_style->i_outline_width = term.val;
76
1.23k
        p_style->i_style_flags |= STYLE_OUTLINE;
77
1.23k
        p_style->i_features |= STYLE_HAS_FLAGS;
78
1.23k
    }
79
1.70k
}
80
81
static void OutlineColor( vlc_css_term_t term, text_style_t *p_style )
82
975
{
83
975
    Color( term, &p_style->i_outline_color, &p_style->i_outline_alpha,
84
975
           &p_style->i_features, STYLE_HAS_OUTLINE_COLOR, STYLE_HAS_OUTLINE_ALPHA );
85
975
}
86
87
static void ShadowDrop( vlc_css_term_t term, text_style_t *p_style )
88
1.07k
{
89
1.07k
    if( term.type >= TYPE_PIXELS )
90
841
    {
91
841
        p_style->i_shadow_width = term.val;
92
841
        p_style->i_style_flags |= STYLE_SHADOW;
93
841
        p_style->i_features |= STYLE_HAS_FLAGS;
94
841
    }
95
1.07k
}
96
97
static void ShadowColor( vlc_css_term_t term, text_style_t *p_style )
98
561
{
99
561
    Color( term, &p_style->i_shadow_color, &p_style->i_shadow_alpha,
100
561
           &p_style->i_features, STYLE_HAS_SHADOW_COLOR, STYLE_HAS_SHADOW_ALPHA );
101
561
}
102
103
void webvtt_FillStyleFromCssDeclaration( const vlc_css_declaration_t *p_decl, text_style_t *p_style )
104
55.0k
{
105
55.0k
    if( !p_decl->psz_property || !p_style )
106
0
        return;
107
108
    /* Only support simple expressions for now */
109
55.0k
    if( !p_decl->expr || p_decl->expr->i_count < 1 )
110
0
        return;
111
112
55.0k
    vlc_css_term_t term0 = p_decl->expr->seq[0].term;
113
114
55.0k
    if( !strcasecmp( p_decl->psz_property, "color" ) )
115
20.3k
    {
116
20.3k
        Color( term0, &p_style->i_font_color, &p_style->i_font_alpha,
117
20.3k
               &p_style->i_features, STYLE_HAS_FONT_COLOR, STYLE_HAS_FONT_ALPHA );
118
20.3k
    }
119
34.6k
    else if( !strcasecmp( p_decl->psz_property, "text-decoration" ) )
120
215
    {
121
215
        if( term0.type == TYPE_STRING )
122
0
        {
123
0
            if( !strcasecmp( term0.psz, "none" ) )
124
0
            {
125
0
                p_style->i_style_flags &= ~(STYLE_STRIKEOUT|STYLE_UNDERLINE);
126
0
                p_style->i_features |= STYLE_HAS_FLAGS;
127
0
            }
128
0
            else if( !strcasecmp( term0.psz, "line-through" ) )
129
0
            {
130
0
                p_style->i_style_flags |= STYLE_STRIKEOUT;
131
0
                p_style->i_features |= STYLE_HAS_FLAGS;
132
0
            }
133
0
            else if( !strcasecmp( term0.psz, "underline" ) )
134
0
            {
135
0
                p_style->i_style_flags |= STYLE_UNDERLINE;
136
0
                p_style->i_features |= STYLE_HAS_FLAGS;
137
0
            }
138
0
        }
139
215
    }
140
34.4k
    else if( !strcasecmp( p_decl->psz_property, "text-shadow" ) )
141
1.07k
    {
142
1.07k
        ShadowDrop( term0, p_style );
143
1.07k
        if( p_decl->expr->i_count == 3 )
144
561
            ShadowColor( p_decl->expr->seq[2].term, p_style );
145
1.07k
    }
146
33.3k
    else if( !strcasecmp( p_decl->psz_property, "background-color" ) )
147
351
    {
148
351
        Color( term0, &p_style->i_background_color, &p_style->i_background_alpha,
149
351
               &p_style->i_features, STYLE_HAS_BACKGROUND_COLOR, STYLE_HAS_BACKGROUND_ALPHA );
150
351
        p_style->i_style_flags |= STYLE_BACKGROUND;
151
351
        p_style->i_features |= STYLE_HAS_FLAGS;
152
351
    }
153
33.0k
    else if( !strcasecmp( p_decl->psz_property, "outline-color" ) )
154
226
    {
155
226
        OutlineColor( term0, p_style );
156
226
    }
157
32.8k
    else if( !strcasecmp( p_decl->psz_property, "outline-width" ) )
158
515
    {
159
515
        OutlineWidth( term0, p_style );
160
515
    }
161
32.2k
    else if( !strcasecmp( p_decl->psz_property, "outline" ) )
162
1.19k
    {
163
1.19k
        OutlineWidth( term0, p_style );
164
1.19k
        if( p_decl->expr->i_count == 3 )
165
749
            OutlineColor( p_decl->expr->seq[2].term, p_style );
166
1.19k
    }
167
31.1k
    else if( !strcasecmp( p_decl->psz_property, "font-family" ) )
168
2.13k
    {
169
2.13k
        vlc_css_term_t *term;
170
2.13k
        if( term0.type >= TYPE_STRING )
171
1.91k
        {
172
1.91k
            size_t i_total = 1 + (p_decl->expr->i_count - 1) * 2;
173
16.4k
            for( size_t i=0; i<p_decl->expr->i_count; i++ )
174
14.5k
            {
175
14.5k
                term = &p_decl->expr->seq[i].term;
176
14.5k
                if( term->type < TYPE_STRING )
177
1.10k
                    continue;
178
13.4k
                i_total += strlen( term->psz );
179
13.4k
                if( term->type == TYPE_STRING )
180
3.80k
                    i_total += 2;
181
13.4k
            }
182
1.91k
            char *psz = malloc( i_total );
183
1.91k
            if( psz )
184
1.91k
            {
185
1.91k
                *psz = 0;
186
16.4k
                for( size_t i=0; i<p_decl->expr->i_count; i++ )
187
14.5k
                {
188
14.5k
                    term = &p_decl->expr->seq[i].term;
189
14.5k
                    if( term->type < TYPE_STRING )
190
1.10k
                        continue;
191
13.4k
                    if( i > 0 )
192
11.5k
                        strcat( psz, ", " );
193
13.4k
                    i_total += strlen( term->psz );
194
13.4k
                    if( term->type == TYPE_STRING )
195
3.80k
                        strcat( psz, "\"" );
196
13.4k
                    strcat( psz, term->psz );
197
13.4k
                    if( term->type == TYPE_STRING )
198
3.80k
                        strcat( psz, "\"" );
199
13.4k
                }
200
1.91k
                free( p_style->psz_fontname );
201
1.91k
                p_style->psz_fontname = psz;
202
1.91k
            }
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.91k
        }
213
2.13k
    }
214
28.9k
    else if( !strcasecmp( p_decl->psz_property, "font-style" ) )
215
1.74k
    {
216
1.74k
        if( term0.type >= TYPE_STRING )
217
1.01k
        {
218
1.01k
            if( !strcasecmp(term0.psz, "normal") )
219
219
            {
220
219
                p_style->i_style_flags &= ~STYLE_ITALIC;
221
219
                p_style->i_features |= STYLE_HAS_FLAGS;
222
219
            }
223
797
            else if( !strcasecmp(term0.psz, "italic") )
224
354
            {
225
354
                p_style->i_style_flags |= STYLE_ITALIC;
226
354
                p_style->i_features |= STYLE_HAS_FLAGS;
227
354
            }
228
1.01k
        }
229
1.74k
    }
230
27.2k
    else if( !strcasecmp( p_decl->psz_property, "font-weight" ) )
231
1.72k
    {
232
1.72k
        if( term0.type >= TYPE_STRING )
233
894
        {
234
894
            if( !strcasecmp(term0.psz, "normal") )
235
228
            {
236
228
                p_style->i_style_flags &= ~STYLE_BOLD;
237
228
                p_style->i_features |= STYLE_HAS_FLAGS;
238
228
            }
239
894
            if( !strcasecmp(term0.psz, "bold") )
240
264
            {
241
264
                p_style->i_style_flags |= STYLE_BOLD;
242
264
                p_style->i_features |= STYLE_HAS_FLAGS;
243
264
            }
244
894
        }
245
826
        else if( term0.type == TYPE_NONE )
246
462
        {
247
462
            if( term0.val >= 700.0 )
248
236
                p_style->i_style_flags |= STYLE_BOLD;
249
226
            else
250
226
                p_style->i_style_flags &= ~STYLE_BOLD;
251
462
            p_style->i_features |= STYLE_HAS_FLAGS;
252
462
        }
253
1.72k
    }
254
25.5k
    else if( !strcasecmp( p_decl->psz_property, "font-size" ) )
255
1.95k
    {
256
1.95k
        if( term0.type == TYPE_PIXELS )
257
435
            p_style->i_font_size = term0.val;
258
1.52k
        else if( term0.type == TYPE_EMS )
259
0
            p_style->f_font_relsize = term0.val * 5.33 / 1.06;
260
1.52k
        else if( term0.type == TYPE_PERCENT )
261
442
            p_style->f_font_relsize = term0.val * 5.33 / 100;
262
1.95k
    }
263
23.5k
    else if( !strcasecmp( p_decl->psz_property, "font" ) )
264
430
    {
265
        /* what to do ? */
266
430
    }
267
23.1k
    else if( !strcasecmp( p_decl->psz_property, "white-space" ) )
268
1.15k
    {
269
1.15k
        if( term0.type >= TYPE_STRING )
270
940
        {
271
940
            if( !strcasecmp(term0.psz, "normal" ) )
272
239
                p_style->e_wrapinfo = STYLE_WRAP_DEFAULT;
273
940
            if( !strcasecmp(term0.psz, "nowrap" ) )
274
234
                p_style->e_wrapinfo = STYLE_WRAP_NONE;
275
940
        }
276
1.15k
    }
277
55.0k
}