1
//! CSS properties, specified values, computed values.
2
//!
3
//! To implement support for a CSS property, do the following:
4
//!
5
//! * Create a type that will hold the property's values.  Please do this in the file
6
//!   `property_defs.rs`; you should cut-and-paste from the existing property definitions or
7
//!   read the documentation of the [`make_property`] macro.  You should read the
8
//!   documentation for the [`property_defs`][crate::property_defs] module to see all that
9
//!   is involved in creating a type for a property.
10
//!
11
//! * Modify the call to the `make_properties` macro in this module to include the new
12
//!   property's name.
13
//!
14
//! * Modify the rest of librsvg wherever the computed value of the property needs to be used.
15
//!   This is available in methods that take an argument of type [`ComputedValues`].
16

            
17
use cssparser::{
18
    self, BasicParseErrorKind, ParseErrorKind, Parser, ParserInput, RuleBodyParser, ToCss,
19
};
20
use markup5ever::{
21
    expanded_name, local_name, namespace_url, ns, ExpandedName, LocalName, QualName,
22
};
23
use std::collections::HashSet;
24

            
25
#[cfg(doc)]
26
use crate::make_property;
27

            
28
use crate::css::{DeclParser, Declaration, Origin, RuleBodyItem};
29
use crate::error::*;
30
use crate::parsers::{Parse, ParseValue};
31
use crate::property_macros::Property;
32
use crate::rsvg_log;
33
use crate::session::Session;
34
use crate::transform::{Transform, TransformAttribute, TransformProperty};
35
use crate::xml::Attributes;
36

            
37
// Re-export the actual properties so they are easy to find from a single place `properties::*`.
38
pub use crate::font_props::*;
39
pub use crate::property_defs::*;
40

            
41
/// Representation of a single CSS property value.
42
///
43
/// `Unspecified` is the `Default`; it means that the corresponding property is not present.
44
///
45
/// `Inherit` means that the property is explicitly set to inherit
46
/// from the parent element.  This is useful for properties which the
47
/// SVG or CSS specs mandate that should not be inherited by default.
48
///
49
/// `Specified` is a value given by the SVG or CSS stylesheet.  This will later be
50
/// resolved into part of a `ComputedValues` struct.
51
1461252
#[derive(Clone)]
52
pub enum SpecifiedValue<T>
53
where
54
    T: Property + Clone + Default,
55
{
56
    Unspecified,
57
    Inherit,
58
1518701
    Specified(T),
59
}
60

            
61
impl<T> SpecifiedValue<T>
62
where
63
    T: Property + Clone + Default,
64
{
65
97046391
    pub fn compute(&self, src: &T, src_values: &ComputedValues) -> T {
66
97046391
        let value: T = match *self {
67
            SpecifiedValue::Unspecified => {
68
95648729
                if <T as Property>::inherits_automatically() {
69
52467792
                    src.clone()
70
                } else {
71
43180937
                    Default::default()
72
                }
73
            }
74

            
75
42
            SpecifiedValue::Inherit => src.clone(),
76

            
77
1397620
            SpecifiedValue::Specified(ref v) => v.clone(),
78
        };
79

            
80
97046391
        value.compute(src_values)
81
97046391
    }
82
}
83

            
84
/// Whether a property also has a presentation attribute.
85
///
86
/// <https://svgwg.org/svg2-draft/styling.html#PresentationAttributes>
87
25487
#[derive(PartialEq)]
88
enum PresentationAttr {
89
    No,
90
    Yes,
91
}
92

            
93
/// How to parse a value, whether it comes from a property or from a presentation attribute
94
58464
#[derive(PartialEq)]
95
pub enum ParseAs {
96
    Property,
97
    PresentationAttr,
98
}
99

            
100
impl PropertyId {
101
98755849
    fn as_u8(&self) -> u8 {
102
98755849
        *self as u8
103
98755849
    }
104

            
105
98097340
    fn as_usize(&self) -> usize {
106
98097340
        *self as usize
107
98097340
    }
108
}
109

            
110
/// Holds the specified values for the CSS properties of an element.
111
#[derive(Clone)]
112
pub struct SpecifiedValues {
113
    indices: [u8; PropertyId::UnsetProperty as usize],
114
    props: Vec<ParsedProperty>,
115

            
116
    transform: Option<Transform>,
117
}
118

            
119
impl Default for SpecifiedValues {
120
1024693
    fn default() -> Self {
121
1024693
        SpecifiedValues {
122
            // this many elements, with the same value
123
1024693
            indices: [PropertyId::UnsetProperty.as_u8(); PropertyId::UnsetProperty as usize],
124
1024693
            props: Vec::new(),
125
1024693
            transform: None,
126
        }
127
1024693
    }
128
}
129

            
130
impl ComputedValues {
131
    // TODO for madds: this function will go away, to be replaced by the one generated
132
    // automatically by the macros.
133
1954867
    pub fn transform(&self) -> Transform {
134
1954867
        self.transform
135
1954867
    }
136

            
137
193
    pub fn is_overflow(&self) -> bool {
138
193
        matches!(self.overflow(), Overflow::Auto | Overflow::Visible)
139
193
    }
140

            
141
    /// Whether we should draw the element or skip both space allocation
142
    /// and drawing.
143
    /// <https://www.w3.org/TR/SVG2/render.html#VisibilityControl>
144
1958346
    pub fn is_displayed(&self) -> bool {
145
1958346
        self.display() != Display::None
146
1958346
    }
147

            
148
    /// Whether we should draw the element or allocate its space but
149
    /// skip drawing.
150
    /// <https://www.w3.org/TR/SVG2/render.html#VisibilityControl>
151
949020
    pub fn is_visible(&self) -> bool {
152
949020
        self.visibility() == Visibility::Visible
153
949020
    }
154
}
155

            
156
/// Macro to generate all the machinery for properties.
157
///
158
/// This generates the following:
159
///
160
/// * `PropertyId`, an fieldless enum with simple values to identify all the properties.
161
/// * `ParsedProperty`, a variant enum for all the specified property values.
162
/// * `ComputedValue`, a variant enum for all the computed values.
163
/// * `parse_value`, the main function to parse a property or attribute value from user input.
164
///
165
/// There is a lot of repetitive code, for example, because sometimes
166
/// we need to operate on `PropertyId::Foo`, `ParsedProperty::Foo` and
167
/// `ComputedValue::Foo` together.  This is why all this is done with a macro.
168
///
169
/// See the only invocation of this macro to see how it is used; it is just
170
/// a declarative list of property names.
171
///
172
/// **NOTE:** If you get a compiler error similar to this:
173
///
174
/// ```text
175
/// 362 |         "mix-blend-mode"              => mix_blend_mode              : MixBlendMode,
176
///     |         ^^^^^^^^^^^^^^^^ no rules expected this token in macro call
177
/// ```
178
///
179
/// Then it may be that you put the name inside the `longhands` block, when it should be
180
/// inside the `longhands_not_supported_by_markup5ever` block.  This is because the
181
/// [`markup5ever`] crate does not have predefined names for every single property out
182
/// there; just the common ones.
183
///
184
/// [`markup5ever`]: https://docs.rs/markup5ever
185
macro_rules! make_properties {
186
    {
187
        shorthands: {
188
            $($short_str:tt => ( $short_presentation_attr:expr, $short_field:ident: $short_name:ident ),)*
189
        }
190

            
191
        longhands: {
192
            $($long_str:tt => ( $long_presentation_attr:expr, $long_field:ident: $long_name:ident ),)+
193
        }
194

            
195
        // These are for when expanded_name!("" "foo") is not defined yet
196
        // in markup5ever.  We create an ExpandedName by hand in that case.
197
        longhands_not_supported_by_markup5ever: {
198
            $($long_m5e_str:tt => ($long_m5e_presentation_attr:expr, $long_m5e_field:ident: $long_m5e_name:ident ),)+
199
        }
200

            
201
        non_properties: {
202
            $($nonprop_field:ident: $nonprop_name:ident,)+
203
        }
204
    }=> {
205
        /// Used to match `ParsedProperty` to their discriminant
206
        ///
207
        /// The `PropertyId::UnsetProperty` can be used as a sentinel value, as
208
        /// it does not match any `ParsedProperty` discriminant; it is really the
209
        /// number of valid values in this enum.
210
        #[repr(u8)]
211
        #[derive(Copy, Clone, PartialEq)]
212
        enum PropertyId {
213
            $($short_name,)+
214
            $($long_name,)+
215
            $($long_m5e_name,)+
216
            $($nonprop_name,)+
217

            
218
            UnsetProperty,
219
        }
220

            
221
        impl PropertyId {
222
242657551
            fn is_shorthand(self) -> bool {
223
242657551
                match self {
224
                    $(PropertyId::$short_name => true,)+
225
242657551
                    _ => false,
226
                }
227
242657551
            }
228
        }
229

            
230
        /// Embodies "which property is this" plus the property's value
231
1461251
        #[derive(Clone)]
232
        pub enum ParsedProperty {
233
            // we put all the properties here; these are for SpecifiedValues
234
            $($short_name(SpecifiedValue<$short_name>),)+
235
1457981
            $($long_name(SpecifiedValue<$long_name>),)+
236
3231
            $($long_m5e_name(SpecifiedValue<$long_m5e_name>),)+
237
39
            $($nonprop_name(SpecifiedValue<$nonprop_name>),)+
238
        }
239

            
240
        enum ComputedValue {
241
            $(
242
                $long_name($long_name),
243
            )+
244

            
245
            $(
246
                $long_m5e_name($long_m5e_name),
247
            )+
248

            
249
            $(
250
                $nonprop_name($nonprop_name),
251
            )+
252
        }
253

            
254
        /// Holds the computed values for the CSS properties of an element.
255
5043048
        #[derive(Debug, Default, Clone)]
256
        pub struct ComputedValues {
257
            $(
258
2522515
                $long_field: $long_name,
259
            )+
260

            
261
            $(
262
2522313
                $long_m5e_field: $long_m5e_name,
263
            )+
264

            
265
            $(
266
2522357
                $nonprop_field: $nonprop_name,
267
            )+
268

            
269
2522344
            transform: Transform,
270
        }
271

            
272
        impl ParsedProperty {
273
63622
            fn get_property_id(&self) -> PropertyId {
274
63622
                match *self {
275
61745
                    $(ParsedProperty::$long_name(_) => PropertyId::$long_name,)+
276
1863
                    $(ParsedProperty::$long_m5e_name(_) => PropertyId::$long_m5e_name,)+
277
                    $(ParsedProperty::$short_name(_) => PropertyId::$short_name,)+
278
14
                    $(ParsedProperty::$nonprop_name(_) => PropertyId::$nonprop_name,)+
279
                }
280
63622
            }
281

            
282
96613359
            fn unspecified(id: PropertyId) -> Self {
283
                use SpecifiedValue::Unspecified;
284

            
285
96613359
                match id {
286
83359977
                    $(PropertyId::$long_name => ParsedProperty::$long_name(Unspecified),)+
287
10288752
                    $(PropertyId::$long_m5e_name => ParsedProperty::$long_m5e_name(Unspecified),)+
288
                    $(PropertyId::$short_name => ParsedProperty::$short_name(Unspecified),)+
289
2964630
                    $(PropertyId::$nonprop_name => ParsedProperty::$nonprop_name(Unspecified),)+
290

            
291
                    PropertyId::UnsetProperty => unreachable!(),
292
                }
293
96613359
            }
294
        }
295

            
296
        impl ComputedValues {
297
            $(
298
128303663
                pub fn $long_field(&self) -> $long_name {
299
128303663
                    if let ComputedValue::$long_name(v) = self.get_value(PropertyId::$long_name) {
300
                        v
301
                    } else {
302
                        unreachable!();
303
                    }
304
128303663
                }
305
            )+
306

            
307
            $(
308
18592616
                pub fn $long_m5e_field(&self) -> $long_m5e_name {
309
18592616
                    if let ComputedValue::$long_m5e_name(v) = self.get_value(PropertyId::$long_m5e_name) {
310
                        v
311
                    } else {
312
                        unreachable!();
313
                    }
314
18592616
                }
315
            )+
316

            
317
            $(
318
2990218
                pub fn $nonprop_field(&self) -> $nonprop_name {
319
2990218
                    if let ComputedValue::$nonprop_name(v) = self.get_value(PropertyId::$nonprop_name) {
320
                        v
321
                    } else {
322
                        unreachable!();
323
                    }
324
2990218
                }
325
            )+
326

            
327
97069647
            fn set_value(&mut self, computed: ComputedValue) {
328
97069647
                match computed {
329
83791533
                    $(ComputedValue::$long_name(v) => self.$long_field = v,)+
330
10290027
                    $(ComputedValue::$long_m5e_name(v) => self.$long_m5e_field = v,)+
331
2988087
                    $(ComputedValue::$nonprop_name(v) => self.$nonprop_field = v,)+
332
                }
333
97069647
            }
334

            
335
149875257
            fn get_value(&self, id: PropertyId) -> ComputedValue {
336
149875257
                assert!(!id.is_shorthand());
337

            
338
149875257
                match id {
339
                    $(
340
                        PropertyId::$long_name =>
341
128294212
                            ComputedValue::$long_name(self.$long_field.clone()),
342
                    )+
343
                    $(
344
                        PropertyId::$long_m5e_name =>
345
18590800
                            ComputedValue::$long_m5e_name(self.$long_m5e_field.clone()),
346
                    )+
347
                    $(
348
                        PropertyId::$nonprop_name =>
349
2990245
                            ComputedValue::$nonprop_name(self.$nonprop_field.clone()),
350
                    )+
351
                    _ => unreachable!(),
352
                }
353
149875257
            }
354
        }
355

            
356
        /// Parses a value from either a style property or from an element's attribute.
357
125929
        pub fn parse_value<'i>(
358
            prop_name: &QualName,
359
            input: &mut Parser<'i, '_>,
360
            parse_as: ParseAs,
361
        ) -> Result<ParsedProperty, ParseError<'i>> {
362
194581
            match prop_name.expanded() {
363
                $(
364
55475
                    expanded_name!("", $long_str) if !(parse_as == ParseAs::PresentationAttr && $long_presentation_attr == PresentationAttr::No) => {
365
55464
                        Ok(ParsedProperty::$long_name(parse_input(input)?))
366
54363
                    }
367
                )+
368

            
369
                $(
370
555445
                    e if e == ExpandedName {
371
555445
                        ns: &ns!(),
372
555445
                        local: &LocalName::from($long_m5e_str),
373
553074
                    } && !(parse_as == ParseAs::PresentationAttr && $long_m5e_presentation_attr == PresentationAttr::No) => {
374
1829
                        Ok(ParsedProperty::$long_m5e_name(parse_input(input)?))
375
1829
                    }
376
                )+
377

            
378
                $(
379
1397
                    expanded_name!("", $short_str) if parse_as == ParseAs::Property => {
380
                        // No shorthand has a presentation attribute.
381
1395
                        assert!($short_presentation_attr == PresentationAttr::No);
382

            
383
1395
                        Ok(ParsedProperty::$short_name(parse_input(input)?))
384
1395
                    }
385
                )+
386

            
387
                _ => {
388
67257
                    let loc = input.current_source_location();
389
67257
                    Err(loc.new_custom_error(ValueErrorKind::UnknownProperty))
390
67257
                }
391
            }
392
125941
        }
393
    };
394
}
395

            
396
#[rustfmt::skip]
397
make_properties! {
398
    shorthands: {
399
        // No shorthand has a presentation attribute.
400
        "font"    => (PresentationAttr::No, font   : Font),
401
        "marker"  => (PresentationAttr::No, marker : Marker),
402
    }
403

            
404
    // longhands that are presentation attributes right now, but need to be turned into properties:
405
    // "d"      - applies only to path
406

            
407
    longhands: {
408
        // "alignment-baseline"       => (PresentationAttr::Yes, unimplemented),
409
        "baseline-shift"              => (PresentationAttr::Yes, baseline_shift              : BaselineShift),
410
        "clip-path"                   => (PresentationAttr::Yes, clip_path                   : ClipPath),
411
        "clip-rule"                   => (PresentationAttr::Yes, clip_rule                   : ClipRule),
412
        "color"                       => (PresentationAttr::Yes, color                       : Color),
413
        // "color-interpolation"      => (PresentationAttr::Yes, unimplemented),
414
        "color-interpolation-filters" => (PresentationAttr::Yes, color_interpolation_filters : ColorInterpolationFilters),
415
        // "cursor"                   => (PresentationAttr::Yes, unimplemented),
416
        "cx"                          => (PresentationAttr::Yes, cx: CX),
417
        "cy"                          => (PresentationAttr::Yes, cy: CY),
418
        "direction"                   => (PresentationAttr::Yes, direction                   : Direction),
419
        "display"                     => (PresentationAttr::Yes, display                     : Display),
420
        // "dominant-baseline"        => (PresentationAttr::Yes, unimplemented),
421
        "enable-background"           => (PresentationAttr::Yes, enable_background           : EnableBackground),
422

            
423
        // "applies to any element except animation elements"
424
        // https://www.w3.org/TR/SVG2/styling.html#PresentationAttributes
425
        "fill"                        => (PresentationAttr::Yes, fill                        : Fill),
426

            
427
        "fill-opacity"                => (PresentationAttr::Yes, fill_opacity                : FillOpacity),
428
        "fill-rule"                   => (PresentationAttr::Yes, fill_rule                   : FillRule),
429
        "filter"                      => (PresentationAttr::Yes, filter                      : Filter),
430
        "flood-color"                 => (PresentationAttr::Yes, flood_color                 : FloodColor),
431
        "flood-opacity"               => (PresentationAttr::Yes, flood_opacity               : FloodOpacity),
432
        "font-family"                 => (PresentationAttr::Yes, font_family                 : FontFamily),
433
        "font-size"                   => (PresentationAttr::Yes, font_size                   : FontSize),
434
        // "font-size-adjust"         => (PresentationAttr::Yes, unimplemented),
435
        "font-stretch"                => (PresentationAttr::Yes, font_stretch                : FontStretch),
436
        "font-style"                  => (PresentationAttr::Yes, font_style                  : FontStyle),
437
        "font-variant"                => (PresentationAttr::Yes, font_variant                : FontVariant),
438
        "font-weight"                 => (PresentationAttr::Yes, font_weight                 : FontWeight),
439

            
440
        // "glyph-orientation-horizontal" - obsolete, removed from SVG2
441

            
442
        // "glyph-orientation-vertical" - obsolete, now shorthand -
443
        // https://svgwg.org/svg2-draft/text.html#GlyphOrientationVerticalProperty
444
        // https://www.w3.org/TR/css-writing-modes-3/#propdef-glyph-orientation-vertical
445
        //
446
        // Note that even though CSS Writing Modes 3 turned glyph-orientation-vertical
447
        // into a shorthand, SVG1.1 still makes it available as a presentation attribute.
448
        // So, we put the property here, not in the shorthands, and deal with it as a
449
        // special case in the text handling code.
450
        "glyph-orientation-vertical"  => (PresentationAttr::Yes, glyph_orientation_vertical  : GlyphOrientationVertical),
451
        "height" => (PresentationAttr::Yes, height: Height),
452

            
453
        "image-rendering"             => (PresentationAttr::Yes, image_rendering             : ImageRendering),
454
        "letter-spacing"              => (PresentationAttr::Yes, letter_spacing              : LetterSpacing),
455
        "lighting-color"              => (PresentationAttr::Yes, lighting_color              : LightingColor),
456
        "marker-end"                  => (PresentationAttr::Yes, marker_end                  : MarkerEnd),
457
        "marker-mid"                  => (PresentationAttr::Yes, marker_mid                  : MarkerMid),
458
        "marker-start"                => (PresentationAttr::Yes, marker_start                : MarkerStart),
459
        "mask"                        => (PresentationAttr::Yes, mask                        : Mask),
460
        "opacity"                     => (PresentationAttr::Yes, opacity                     : Opacity),
461
        "overflow"                    => (PresentationAttr::Yes, overflow                    : Overflow),
462
        // "pointer-events"           => (PresentationAttr::Yes, unimplemented),
463
        "r"                           => (PresentationAttr::Yes, r: R),
464
        "rx"                          => (PresentationAttr::Yes, rx: RX),
465
        "ry"                          => (PresentationAttr::Yes, ry: RY),
466
        "shape-rendering"             => (PresentationAttr::Yes, shape_rendering             : ShapeRendering),
467
        "stop-color"                  => (PresentationAttr::Yes, stop_color                  : StopColor),
468
        "stop-opacity"                => (PresentationAttr::Yes, stop_opacity                : StopOpacity),
469
        "stroke"                      => (PresentationAttr::Yes, stroke                      : Stroke),
470
        "stroke-dasharray"            => (PresentationAttr::Yes, stroke_dasharray            : StrokeDasharray),
471
        "stroke-dashoffset"           => (PresentationAttr::Yes, stroke_dashoffset           : StrokeDashoffset),
472
        "stroke-linecap"              => (PresentationAttr::Yes, stroke_line_cap             : StrokeLinecap),
473
        "stroke-linejoin"             => (PresentationAttr::Yes, stroke_line_join            : StrokeLinejoin),
474
        "stroke-miterlimit"           => (PresentationAttr::Yes, stroke_miterlimit           : StrokeMiterlimit),
475
        "stroke-opacity"              => (PresentationAttr::Yes, stroke_opacity              : StrokeOpacity),
476
        "stroke-width"                => (PresentationAttr::Yes, stroke_width                : StrokeWidth),
477
        "text-anchor"                 => (PresentationAttr::Yes, text_anchor                 : TextAnchor),
478
        "text-decoration"             => (PresentationAttr::Yes, text_decoration             : TextDecoration),
479
        // "text-overflow"            => (PresentationAttr::Yes, unimplemented),
480
        "text-rendering"              => (PresentationAttr::Yes, text_rendering              : TextRendering),
481

            
482
        // "transform" - Special case as presentation attribute:
483
        // The SVG1.1 "transform" attribute has a different grammar than the
484
        // SVG2 "transform" property.  Here we define for the properties machinery,
485
        // and it is handled specially as an attribute in parse_presentation_attributes().
486
        "transform"                   => (PresentationAttr::No, transform_property           : TransformProperty),
487

            
488
        // "transform-box"            => (PresentationAttr::Yes, unimplemented),
489
        // "transform-origin"         => (PresentationAttr::Yes, unimplemented),
490
        "unicode-bidi"                => (PresentationAttr::Yes, unicode_bidi                : UnicodeBidi),
491
        "visibility"                  => (PresentationAttr::Yes, visibility                  : Visibility),
492
        // "word-spacing"             => (PresentationAttr::Yes, unimplemented),
493
        "width"                       => (PresentationAttr::Yes, width: Width),
494
        "writing-mode"                => (PresentationAttr::Yes, writing_mode                : WritingMode),
495
        "x"                           => (PresentationAttr::Yes, x: X),
496
        "y"                           => (PresentationAttr::Yes, y: Y),
497
    }
498
    
499
    longhands_not_supported_by_markup5ever: {
500
        "isolation"                   => (PresentationAttr::No,  isolation                   : Isolation),
501
        "line-height"                 => (PresentationAttr::No,  line_height                 : LineHeight),
502
        "mask-type"                   => (PresentationAttr::Yes, mask_type                   : MaskType),
503
        "mix-blend-mode"              => (PresentationAttr::No,  mix_blend_mode              : MixBlendMode),
504
        "paint-order"                 => (PresentationAttr::Yes, paint_order                 : PaintOrder),
505
        "text-orientation"            => (PresentationAttr::No,  text_orientation            : TextOrientation),
506
        "vector-effect"               => (PresentationAttr::Yes, vector_effect               : VectorEffect),
507
        "white-space"                 => (PresentationAttr::Yes, white_space                 : WhiteSpace),
508
    }
509

            
510
    // These are not properties, but presentation attributes.  However,
511
    // both xml:lang and xml:space *do* inherit.  We are abusing the
512
    // property inheritance code for these XML-specific attributes.
513
    non_properties: {
514
        xml_lang: XmlLang,
515
        xml_space: XmlSpace,
516
    }
517
}
518

            
519
impl SpecifiedValues {
520
98038097
    fn property_index(&self, id: PropertyId) -> Option<usize> {
521
98038097
        let v = self.indices[id.as_usize()];
522

            
523
98038097
        if v == PropertyId::UnsetProperty.as_u8() {
524
96639897
            None
525
        } else {
526
1398200
            Some(v as usize)
527
        }
528
98038097
    }
529

            
530
63532
    fn set_property(&mut self, prop: &ParsedProperty, replace: bool) {
531
63532
        let id = prop.get_property_id();
532
63532
        assert!(!id.is_shorthand());
533

            
534
126449
        if let Some(index) = self.property_index(id) {
535
1204
            if replace {
536
589
                self.props[index] = prop.clone();
537
            }
538
        } else {
539
62917
            self.props.push(prop.clone());
540
62917
            let pos = self.props.len() - 1;
541
62917
            self.indices[id.as_usize()] = pos as u8;
542
        }
543
63532
    }
544

            
545
97978301
    fn get_property(&self, id: PropertyId) -> ParsedProperty {
546
97978301
        assert!(!id.is_shorthand());
547

            
548
97978301
        if let Some(index) = self.property_index(id) {
549
1397576
            self.props[index].clone()
550
        } else {
551
96580725
            ParsedProperty::unspecified(id)
552
        }
553
97978301
    }
554

            
555
60489
    fn set_property_expanding_shorthands(&mut self, prop: &ParsedProperty, replace: bool) {
556
60489
        match *prop {
557
32
            ParsedProperty::Font(SpecifiedValue::Specified(ref f)) => {
558
32
                self.expand_font_shorthand(f, replace)
559
            }
560
1371
            ParsedProperty::Marker(SpecifiedValue::Specified(ref m)) => {
561
1371
                self.expand_marker_shorthand(m, replace)
562
            }
563
            ParsedProperty::Font(SpecifiedValue::Inherit) => {
564
1
                self.expand_font_shorthand_inherit(replace)
565
            }
566
            ParsedProperty::Marker(SpecifiedValue::Inherit) => {
567
1
                self.expand_marker_shorthand_inherit(replace)
568
            }
569

            
570
59084
            _ => self.set_property(prop, replace),
571
        }
572
60489
    }
573

            
574
32
    fn expand_font_shorthand(&mut self, font: &Font, replace: bool) {
575
        let FontSpec {
576
32
            style,
577
32
            variant,
578
32
            weight,
579
32
            stretch,
580
32
            size,
581
32
            line_height,
582
32
            family,
583
32
        } = font.to_font_spec();
584

            
585
32
        self.set_property(
586
32
            &ParsedProperty::FontStyle(SpecifiedValue::Specified(style)),
587
            replace,
588
32
        );
589
32
        self.set_property(
590
32
            &ParsedProperty::FontVariant(SpecifiedValue::Specified(variant)),
591
            replace,
592
32
        );
593
32
        self.set_property(
594
32
            &ParsedProperty::FontWeight(SpecifiedValue::Specified(weight)),
595
            replace,
596
32
        );
597
32
        self.set_property(
598
32
            &ParsedProperty::FontStretch(SpecifiedValue::Specified(stretch)),
599
            replace,
600
32
        );
601
32
        self.set_property(
602
32
            &ParsedProperty::FontSize(SpecifiedValue::Specified(size)),
603
            replace,
604
32
        );
605
32
        self.set_property(
606
32
            &ParsedProperty::LineHeight(SpecifiedValue::Specified(line_height)),
607
            replace,
608
32
        );
609
32
        self.set_property(
610
32
            &ParsedProperty::FontFamily(SpecifiedValue::Specified(family)),
611
            replace,
612
32
        );
613
32
    }
614

            
615
1372
    fn expand_marker_shorthand(&mut self, marker: &Marker, replace: bool) {
616
1372
        let Marker(v) = marker;
617

            
618
1372
        self.set_property(
619
1372
            &ParsedProperty::MarkerStart(SpecifiedValue::Specified(MarkerStart(v.clone()))),
620
            replace,
621
1372
        );
622
1372
        self.set_property(
623
1372
            &ParsedProperty::MarkerMid(SpecifiedValue::Specified(MarkerMid(v.clone()))),
624
            replace,
625
1372
        );
626
1372
        self.set_property(
627
1372
            &ParsedProperty::MarkerEnd(SpecifiedValue::Specified(MarkerEnd(v.clone()))),
628
            replace,
629
1372
        );
630
1372
    }
631

            
632
1
    fn expand_font_shorthand_inherit(&mut self, replace: bool) {
633
1
        self.set_property(&ParsedProperty::FontStyle(SpecifiedValue::Inherit), replace);
634
1
        self.set_property(
635
            &ParsedProperty::FontVariant(SpecifiedValue::Inherit),
636
            replace,
637
        );
638
1
        self.set_property(
639
            &ParsedProperty::FontWeight(SpecifiedValue::Inherit),
640
            replace,
641
        );
642
1
        self.set_property(
643
            &ParsedProperty::FontStretch(SpecifiedValue::Inherit),
644
            replace,
645
        );
646
1
        self.set_property(&ParsedProperty::FontSize(SpecifiedValue::Inherit), replace);
647
1
        self.set_property(
648
            &ParsedProperty::LineHeight(SpecifiedValue::Inherit),
649
            replace,
650
        );
651
1
        self.set_property(
652
            &ParsedProperty::FontFamily(SpecifiedValue::Inherit),
653
            replace,
654
        );
655
1
    }
656

            
657
1
    fn expand_marker_shorthand_inherit(&mut self, replace: bool) {
658
1
        self.set_property(
659
            &ParsedProperty::MarkerStart(SpecifiedValue::Inherit),
660
            replace,
661
        );
662
1
        self.set_property(&ParsedProperty::MarkerMid(SpecifiedValue::Inherit), replace);
663
1
        self.set_property(&ParsedProperty::MarkerEnd(SpecifiedValue::Inherit), replace);
664
1
    }
665

            
666
57416
    pub fn set_parsed_property(&mut self, prop: &ParsedProperty) {
667
57416
        self.set_property_expanding_shorthands(prop, true);
668
57416
    }
669

            
670
    /* user agent property have less priority than presentation attributes */
671
3083
    pub fn set_parsed_property_user_agent(&mut self, prop: &ParsedProperty) {
672
3083
        self.set_property_expanding_shorthands(prop, false);
673
3083
    }
674

            
675
1470047
    pub fn to_computed_values(&self, computed: &mut ComputedValues) {
676
        macro_rules! compute {
677
1470047
            ($name:ident, $field:ident) => {{
678
                // This extra block --------^
679
                // is so that prop_val will be dropped within the macro invocation;
680
                // otherwise all the temporary values cause this function to use
681
                // an unreasonably large amount of stack space.
682
97005886
                let prop_val = self.get_property(PropertyId::$name);
683
97005886
                if let ParsedProperty::$name(s) = prop_val {
684
97021656
                    computed.set_value(ComputedValue::$name(
685
97005886
                        s.compute(&computed.$field(), computed),
686
17640398
                    ));
687
17637634
                } else {
688
                    unreachable!();
689
                }
690
97005346
            }};
691
        }
692

            
693
        // First, compute font_size.  It needs to be done before everything
694
        // else, so that properties that depend on its computed value
695
        // will be able to use it.  For example, baseline-shift
696
        // depends on font-size.
697

            
698
        compute!(FontSize, font_size);
699

            
700
        // Then, do all the other properties.
701

            
702
        compute!(BaselineShift, baseline_shift);
703
        compute!(ClipPath, clip_path);
704
        compute!(ClipRule, clip_rule);
705
        compute!(Color, color);
706
        compute!(ColorInterpolationFilters, color_interpolation_filters);
707
        compute!(CX, cx);
708
        compute!(CY, cy);
709
        compute!(Direction, direction);
710
        compute!(Display, display);
711
        compute!(EnableBackground, enable_background);
712
        compute!(Fill, fill);
713
        compute!(FillOpacity, fill_opacity);
714
        compute!(FillRule, fill_rule);
715
        compute!(Filter, filter);
716
        compute!(FloodColor, flood_color);
717
        compute!(FloodOpacity, flood_opacity);
718
        compute!(FontFamily, font_family);
719
        compute!(FontStretch, font_stretch);
720
        compute!(FontStyle, font_style);
721
        compute!(FontVariant, font_variant);
722
        compute!(FontWeight, font_weight);
723
        compute!(GlyphOrientationVertical, glyph_orientation_vertical);
724
        compute!(Height, height);
725
        compute!(ImageRendering, image_rendering);
726
        compute!(Isolation, isolation);
727
        compute!(LetterSpacing, letter_spacing);
728
        compute!(LightingColor, lighting_color);
729
        compute!(MarkerEnd, marker_end);
730
        compute!(MarkerMid, marker_mid);
731
        compute!(MarkerStart, marker_start);
732
        compute!(Mask, mask);
733
        compute!(MaskType, mask_type);
734
        compute!(MixBlendMode, mix_blend_mode);
735
        compute!(Opacity, opacity);
736
        compute!(Overflow, overflow);
737
        compute!(PaintOrder, paint_order);
738
        compute!(R, r);
739
        compute!(RX, rx);
740
        compute!(RY, ry);
741
        compute!(ShapeRendering, shape_rendering);
742
        compute!(StopColor, stop_color);
743
        compute!(StopOpacity, stop_opacity);
744
        compute!(Stroke, stroke);
745
        compute!(StrokeDasharray, stroke_dasharray);
746
        compute!(StrokeDashoffset, stroke_dashoffset);
747
        compute!(StrokeLinecap, stroke_line_cap);
748
        compute!(StrokeLinejoin, stroke_line_join);
749
        compute!(StrokeOpacity, stroke_opacity);
750
        compute!(StrokeMiterlimit, stroke_miterlimit);
751
        compute!(StrokeWidth, stroke_width);
752
        compute!(TextAnchor, text_anchor);
753
        compute!(TextDecoration, text_decoration);
754
        compute!(TextOrientation, text_orientation);
755
        compute!(TextRendering, text_rendering);
756
        compute!(TransformProperty, transform_property);
757
        compute!(UnicodeBidi, unicode_bidi);
758
        compute!(VectorEffect, vector_effect);
759
        compute!(Visibility, visibility);
760
        compute!(Width, width);
761
        compute!(WhiteSpace, white_space);
762
        compute!(WritingMode, writing_mode);
763
        compute!(X, x);
764
        compute!(XmlSpace, xml_space);
765
        compute!(XmlLang, xml_lang);
766
        compute!(Y, y);
767

            
768
2433944
        computed.transform = self.transform.unwrap_or_else(|| {
769
964437
            match self.get_property(PropertyId::TransformProperty) {
770
2
                ParsedProperty::TransformProperty(SpecifiedValue::Specified(ref t)) => {
771
2
                    t.to_transform()
772
                }
773
964435
                _ => Transform::identity(),
774
            }
775
964437
        });
776
1469507
    }
777

            
778
    /// This is a somewhat egregious hack to allow xml:lang to be stored as a presentational
779
    /// attribute. Presentational attributes can often be influenced by stylesheets,
780
    /// so they're cascaded after selector matching is done, but xml:lang can be queried by
781
    /// CSS selectors, so they need to be cascaded *first*.
782
24629
    pub fn inherit_xml_lang(
783
        &self,
784
        computed: &mut ComputedValues,
785
        parent: Option<crate::node::Node>,
786
    ) {
787
        use crate::node::NodeBorrow;
788
24629
        let prop_val = self.get_property(PropertyId::XmlLang);
789
71703
        if let ParsedProperty::XmlLang(s) = prop_val {
790
71703
            if let Some(parent) = parent {
791
23526
                computed.set_value(ComputedValue::XmlLang(
792
23551
                    parent.borrow_element().get_computed_values().xml_lang(),
793
23519
                ));
794
23515
            }
795
24621
            computed.set_value(ComputedValue::XmlLang(
796
48152
                s.compute(&computed.xml_lang(), computed),
797
24613
            ));
798
24607
        } else {
799
            unreachable!();
800
        }
801
24607
    }
802

            
803
    pub fn is_overflow(&self) -> bool {
804
        if let Some(overflow_index) = self.property_index(PropertyId::Overflow) {
805
            match self.props[overflow_index] {
806
                ParsedProperty::Overflow(SpecifiedValue::Specified(Overflow::Auto)) => true,
807
                ParsedProperty::Overflow(SpecifiedValue::Specified(Overflow::Visible)) => true,
808
                ParsedProperty::Overflow(_) => false,
809
                _ => unreachable!(),
810
            }
811
        } else {
812
            false
813
        }
814
    }
815

            
816
86078
    fn parse_one_presentation_attribute(&mut self, session: &Session, attr: QualName, value: &str) {
817
86272
        let mut input = ParserInput::new(value);
818
86175
        let mut parser = Parser::new(&mut input);
819

            
820
86116
        match parse_value(&attr, &mut parser, ParseAs::PresentationAttr) {
821
23017
            Ok(prop) => {
822
23017
                if parser.expect_exhausted().is_ok() {
823
22995
                    self.set_parsed_property(&prop);
824
                } else {
825
                    rsvg_log!(
826
                        session,
827
                        "(ignoring invalid presentation attribute {:?}\n    value=\"{}\")\n",
828
                        attr.expanded(),
829
                        value,
830
                    );
831
                }
832
23013
            }
833

            
834
            // not a presentation attribute; just ignore it
835
            Err(ParseError {
836
                kind: ParseErrorKind::Custom(ValueErrorKind::UnknownProperty),
837
                ..
838
            }) => (),
839

            
840
            // https://www.w3.org/TR/CSS2/syndata.html#unsupported-values
841
            // For all the following cases, ignore illegal values; don't set the whole node to
842
            // be in error in that case.
843
            Err(ParseError {
844
21
                kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)),
845
                ..
846
            }) => {
847
21
                let mut tok = String::new();
848

            
849
21
                t.to_css(&mut tok).unwrap(); // FIXME: what do we do with a fmt::Error?
850
                rsvg_log!(
851
                    session,
852
                    "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    \
853
                     unexpected token '{}')",
854
                    attr.expanded(),
855
                    value,
856
                    tok,
857
                );
858
21
            }
859

            
860
            Err(ParseError {
861
                kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
862
                ..
863
            }) => {
864
                rsvg_log!(
865
                    session,
866
                    "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    \
867
                     unexpected end of input)",
868
                    attr.expanded(),
869
                    value,
870
                );
871
            }
872

            
873
            Err(ParseError {
874
                kind: ParseErrorKind::Basic(_),
875
                ..
876
            }) => {
877
                rsvg_log!(
878
                    session,
879
                    "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    \
880
                     unexpected error)",
881
                    attr.expanded(),
882
                    value,
883
                );
884
            }
885

            
886
            Err(ParseError {
887
1075
                kind: ParseErrorKind::Custom(ref v),
888
                ..
889
            }) => {
890
                rsvg_log!(
891
                    session,
892
                    "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    {})",
893
                    attr.expanded(),
894
                    value,
895
                    v
896
                );
897
            }
898
        }
899
86129
    }
900

            
901
1024719
    pub fn parse_presentation_attributes(&mut self, session: &Session, attrs: &Attributes) {
902
1116216
        for (attr, value) in attrs.iter() {
903
91889
            match attr.expanded() {
904
                expanded_name!("", "transform") => {
905
                    // FIXME: we parse the transform attribute here because we don't yet have
906
                    // a better way to distinguish attributes whose values have different
907
                    // grammars than properties.
908
5580
                    let transform_attr = TransformAttribute::parse_str(value)
909
71
                        .unwrap_or_else(|_| TransformAttribute::default());
910
5578
                    self.transform = Some(transform_attr.to_transform());
911
5577
                }
912

            
913
                expanded_name!(xml "lang") => {
914
                    // xml:lang is a non-presentation attribute and as such cannot have the
915
                    // "inherit" value.  So, we don't call parse_one_presentation_attribute()
916
                    // for it, but rather call its parser directly.
917
11
                    let parse_result: Result<XmlLang, _> = attr.parse(value);
918
11
                    match parse_result {
919
11
                        Ok(lang) => {
920
11
                            self.set_parsed_property(&ParsedProperty::XmlLang(
921
11
                                SpecifiedValue::Specified(lang),
922
11
                            ));
923
                        }
924

            
925
                        Err(e) => {
926
                            rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
927
                        }
928
                    }
929
                }
930

            
931
                expanded_name!(xml "space") => {
932
                    // xml:space is a non-presentation attribute and as such cannot have the
933
                    // "inherit" value.  So, we don't call parse_one_presentation_attribute()
934
                    // for it, but rather call its parser directly.
935
3
                    let parse_result: Result<XmlSpace, _> = attr.parse(value);
936
3
                    match parse_result {
937
3
                        Ok(space) => {
938
3
                            self.set_parsed_property(&ParsedProperty::XmlSpace(
939
3
                                SpecifiedValue::Specified(space),
940
3
                            ));
941
                        }
942

            
943
                        Err(e) => {
944
                            rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
945
                        }
946
                    }
947
                }
948

            
949
86095
                _ => self.parse_one_presentation_attribute(session, attr, value),
950
            }
951
91589
        }
952
1024327
    }
953

            
954
37579
    pub fn set_property_from_declaration(
955
        &mut self,
956
        declaration: &Declaration,
957
        origin: Origin,
958
        important_styles: &mut HashSet<QualName>,
959
    ) {
960
37579
        if !declaration.important && important_styles.contains(&declaration.prop_name) {
961
            return;
962
        }
963

            
964
37510
        if declaration.important {
965
2656
            important_styles.insert(declaration.prop_name.clone());
966
        }
967

            
968
37510
        if origin == Origin::UserAgent {
969
3084
            self.set_parsed_property_user_agent(&declaration.property);
970
        } else {
971
34426
            self.set_parsed_property(&declaration.property);
972
        }
973
37579
    }
974

            
975
5188
    pub fn parse_style_declarations(
976
        &mut self,
977
        declarations: &str,
978
        origin: Origin,
979
        important_styles: &mut HashSet<QualName>,
980
        session: &Session,
981
    ) {
982
5196
        let mut input = ParserInput::new(declarations);
983
5196
        let mut parser = Parser::new(&mut input);
984

            
985
5192
        RuleBodyParser::new(&mut parser, &mut DeclParser)
986
39146
            .filter_map(|r| match r {
987
33959
                Ok(RuleBodyItem::Decl(decl)) => Some(decl),
988
                Ok(RuleBodyItem::Rule(_)) => None,
989
5187
                Err(e) => {
990
5187
                    rsvg_log!(session, "Invalid declaration; ignoring: {:?}", e);
991
5187
                    None
992
5187
                }
993
39146
            })
994
39198
            .for_each(|decl| self.set_property_from_declaration(&decl, origin, important_styles));
995
5186
    }
996
}
997

            
998
// Parses the value for the type `T` of the property out of the Parser, including `inherit` values.
999
58702
fn parse_input<'i, T>(input: &mut Parser<'i, '_>) -> Result<SpecifiedValue<T>, ParseError<'i>>
where
    T: Property + Clone + Default + Parse,
{
58702
    if input
58689
        .try_parse(|p| p.expect_ident_matching("inherit"))
58702
        .is_ok()
    {
30
        Ok(SpecifiedValue::Inherit)
    } else {
58672
        Parse::parse(input).map(SpecifiedValue::Specified)
    }
58702
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::iri::Iri;
    use crate::length::*;
    #[test]
2
    fn empty_values_computes_to_defaults() {
1
        let specified = SpecifiedValues::default();
1
        let mut computed = ComputedValues::default();
1
        specified.to_computed_values(&mut computed);
1
        assert_eq!(computed.stroke_width(), StrokeWidth::default());
2
    }
    #[test]
2
    fn set_one_property() {
1
        let length = Length::<Both>::new(42.0, LengthUnit::Px);
1
        let mut specified = SpecifiedValues::default();
1
        specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
            StrokeWidth(length),
1
        )));
1
        let mut computed = ComputedValues::default();
1
        specified.to_computed_values(&mut computed);
1
        assert_eq!(computed.stroke_width(), StrokeWidth(length));
2
    }
    #[test]
2
    fn replace_existing_property() {
1
        let length1 = Length::<Both>::new(42.0, LengthUnit::Px);
1
        let length2 = Length::<Both>::new(42.0, LengthUnit::Px);
1
        let mut specified = SpecifiedValues::default();
1
        specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
            StrokeWidth(length1),
1
        )));
1
        specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
            StrokeWidth(length2),
1
        )));
1
        let mut computed = ComputedValues::default();
1
        specified.to_computed_values(&mut computed);
1
        assert_eq!(computed.stroke_width(), StrokeWidth(length2));
2
    }
    #[test]
2
    fn expands_marker_shorthand() {
1
        let mut specified = SpecifiedValues::default();
1
        let iri = Iri::parse_str("url(#foo)").unwrap();
1
        let marker = Marker(iri.clone());
1
        specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker)));
1
        let mut computed = ComputedValues::default();
1
        specified.to_computed_values(&mut computed);
2
        assert_eq!(computed.marker_start(), MarkerStart(iri.clone()));
2
        assert_eq!(computed.marker_mid(), MarkerMid(iri.clone()));
2
        assert_eq!(computed.marker_end(), MarkerEnd(iri.clone()));
2
    }
    #[test]
2
    fn replaces_marker_shorthand() {
1
        let mut specified = SpecifiedValues::default();
1
        let iri1 = Iri::parse_str("url(#foo)").unwrap();
1
        let iri2 = Iri::None;
1
        let marker1 = Marker(iri1.clone());
1
        specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker1)));
1
        let marker2 = Marker(iri2.clone());
1
        specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker2)));
1
        let mut computed = ComputedValues::default();
1
        specified.to_computed_values(&mut computed);
2
        assert_eq!(computed.marker_start(), MarkerStart(iri2.clone()));
2
        assert_eq!(computed.marker_mid(), MarkerMid(iri2.clone()));
2
        assert_eq!(computed.marker_end(), MarkerEnd(iri2.clone()));
2
    }
    #[test]
2
    fn computes_property_that_does_not_inherit_automatically() {
1
        assert!(!<Opacity as Property>::inherits_automatically());
1
        let half_opacity = Opacity::parse_str("0.5").unwrap();
        // first level, as specified with opacity
1
        let mut with_opacity = SpecifiedValues::default();
1
        with_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Specified(
1
            half_opacity.clone(),
1
        )));
1
        let mut computed_0_5 = ComputedValues::default();
1
        with_opacity.to_computed_values(&mut computed_0_5);
1
        assert_eq!(computed_0_5.opacity(), half_opacity.clone());
        // second level, no opacity specified, and it doesn't inherit
1
        let without_opacity = SpecifiedValues::default();
1
        let mut computed = computed_0_5.clone();
1
        without_opacity.to_computed_values(&mut computed);
1
        assert_eq!(computed.opacity(), Opacity::default());
        // another at second level, opacity set to explicitly inherit
1
        let mut with_inherit_opacity = SpecifiedValues::default();
1
        with_inherit_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Inherit));
1
        let mut computed = computed_0_5.clone();
1
        with_inherit_opacity.to_computed_values(&mut computed);
1
        assert_eq!(computed.opacity(), half_opacity.clone());
2
    }
}