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
1460533
#[derive(Clone)]
52
pub enum SpecifiedValue<T>
53
where
54
    T: Property + Clone + Default,
55
{
56
    Unspecified,
57
    Inherit,
58
1517941
    Specified(T),
59
}
60

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

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

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

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

            
84
/// Whether a property also has a presentation attribute.
85
///
86
/// <https://svgwg.org/svg2-draft/styling.html#PresentationAttributes>
87
24199
#[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
57332
#[derive(PartialEq)]
95
pub enum ParseAs {
96
    Property,
97
    PresentationAttr,
98
}
99

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

            
105
96447097
    fn as_usize(&self) -> usize {
106
96447097
        *self as usize
107
96447097
    }
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
1022267
    fn default() -> Self {
121
1022267
        SpecifiedValues {
122
            // this many elements, with the same value
123
1022267
            indices: [PropertyId::UnsetProperty.as_u8(); PropertyId::UnsetProperty as usize],
124
1022267
            props: Vec::new(),
125
1022267
            transform: None,
126
        }
127
1022267
    }
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
1954718
    pub fn transform(&self) -> Transform {
134
1954718
        self.transform
135
1954718
    }
136

            
137
1320
    pub fn is_overflow(&self) -> bool {
138
1320
        matches!(self.overflow(), Overflow::Auto | Overflow::Visible)
139
1320
    }
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
1957849
    pub fn is_displayed(&self) -> bool {
145
1957849
        self.display() != Display::None
146
1957849
    }
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
949327
    pub fn is_visible(&self) -> bool {
152
949327
        self.visibility() == Visibility::Visible
153
949327
    }
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
239571243
            fn is_shorthand(self) -> bool {
223
239571243
                match self {
224
                    $(PropertyId::$short_name => true,)+
225
239571243
                    _ => false,
226
                }
227
239571243
            }
228
        }
229

            
230
        /// Embodies "which property is this" plus the property's value
231
1460536
        #[derive(Clone)]
232
        pub enum ParsedProperty {
233
            // we put all the properties here; these are for SpecifiedValues
234
            $($short_name(SpecifiedValue<$short_name>),)+
235
1457366
            $($long_name(SpecifiedValue<$long_name>),)+
236
3103
            $($long_m5e_name(SpecifiedValue<$long_m5e_name>),)+
237
67
            $($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
5028378
        #[derive(Debug, Default, Clone)]
256
        pub struct ComputedValues {
257
            $(
258
2514690
                $long_field: $long_name,
259
            )+
260

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

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

            
269
2514641
            transform: Transform,
270
        }
271

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

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

            
285
94944642
                match id {
286
83187422
                    $(PropertyId::$long_name => ParsedProperty::$long_name(Unspecified),)+
287
8800966
                    $(PropertyId::$long_m5e_name => ParsedProperty::$long_m5e_name(Unspecified),)+
288
                    $(PropertyId::$short_name => ParsedProperty::$short_name(Unspecified),)+
289
2956254
                    $(PropertyId::$nonprop_name => ParsedProperty::$nonprop_name(Unspecified),)+
290

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

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

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

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

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

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

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

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

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

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

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

            
387
                _ => {
388
66185
                    let loc = input.current_source_location();
389
66185
                    Err(loc.new_custom_error(ValueErrorKind::UnknownProperty))
390
66185
                }
391
            }
392
123741
        }
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
        // "white-space"              => (PresentationAttr::Yes, unimplemented),
493
        // "word-spacing"             => (PresentationAttr::Yes, unimplemented),
494
        "width"                       => (PresentationAttr::Yes, width: Width),
495
        "writing-mode"                => (PresentationAttr::Yes, writing_mode                : WritingMode),
496
        "x"                           => (PresentationAttr::Yes, x: X),
497
        "y"                           => (PresentationAttr::Yes, y: Y),
498
    }
499

            
500
    longhands_not_supported_by_markup5ever: {
501
        "isolation"                   => (PresentationAttr::No,  isolation                   : Isolation),
502
        "line-height"                 => (PresentationAttr::No,  line_height                 : LineHeight),
503
        "mask-type"                   => (PresentationAttr::Yes, mask_type                   : MaskType),
504
        "mix-blend-mode"              => (PresentationAttr::No,  mix_blend_mode              : MixBlendMode),
505
        "paint-order"                 => (PresentationAttr::Yes, paint_order                 : PaintOrder),
506
        "text-orientation"            => (PresentationAttr::No,  text_orientation            : TextOrientation),
507
        "vector-effect"               => (PresentationAttr::Yes, vector_effect               : VectorEffect),
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
96385912
    fn property_index(&self, id: PropertyId) -> Option<usize> {
521
96385912
        let v = self.indices[id.as_usize()];
522

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

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

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

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

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

            
555
60299
    fn set_property_expanding_shorthands(&mut self, prop: &ParsedProperty, replace: bool) {
556
60299
        match *prop {
557
32
            ParsedProperty::Font(SpecifiedValue::Specified(ref f)) => {
558
32
                self.expand_font_shorthand(f, replace)
559
            }
560
1372
            ParsedProperty::Marker(SpecifiedValue::Specified(ref m)) => {
561
1372
                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
58893
            _ => self.set_property(prop, replace),
571
        }
572
60299
    }
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
57393
    pub fn set_parsed_property(&mut self, prop: &ParsedProperty) {
667
57393
        self.set_property_expanding_shorthands(prop, true);
668
57393
    }
669

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

            
675
1467049
    pub fn to_computed_values(&self, computed: &mut ComputedValues) {
676
        macro_rules! compute {
677
            ($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
                let prop_val = self.get_property(PropertyId::$name);
683
                if let ParsedProperty::$name(s) = prop_val {
684
                    computed.set_value(ComputedValue::$name(
685
                        s.compute(&computed.$field(), computed),
686
                    ));
687
                } else {
688
                    unreachable!();
689
                }
690
            }};
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
1467049
        compute!(FontSize, font_size);
699

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

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

            
767
2428258
        computed.transform = self.transform.unwrap_or_else(|| {
768
961531
            match self.get_property(PropertyId::TransformProperty) {
769
2
                ParsedProperty::TransformProperty(SpecifiedValue::Specified(ref t)) => {
770
2
                    t.to_transform()
771
                }
772
961529
                _ => Transform::identity(),
773
            }
774
961531
        });
775
1466727
    }
776

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

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

            
815
83664
    fn parse_one_presentation_attribute(&mut self, session: &Session, attr: QualName, value: &str) {
816
83782
        let mut input = ParserInput::new(value);
817
83723
        let mut parser = Parser::new(&mut input);
818

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

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

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

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

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

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

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

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

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

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

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

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

            
948
83670
                _ => self.parse_one_presentation_attribute(session, attr, value),
949
            }
950
89088
        }
951
1022012
    }
952

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

            
963
37514
        if declaration.important {
964
2651
            important_styles.insert(declaration.prop_name.clone());
965
        }
966

            
967
37514
        if origin == Origin::UserAgent {
968
2919
            self.set_parsed_property_user_agent(&declaration.property);
969
        } else {
970
34595
            self.set_parsed_property(&declaration.property);
971
        }
972
37556
    }
973

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

            
984
5216
        RuleBodyParser::new(&mut parser, &mut DeclParser)
985
44636
            .filter_map(|r| match r {
986
34134
                Ok(RuleBodyItem::Decl(decl)) => Some(decl),
987
                Ok(RuleBodyItem::Rule(_)) => None,
988
5281
                Err(e) => {
989
5281
                    rsvg_log!(session, "Invalid declaration; ignoring: {:?}", e);
990
5281
                    None
991
5281
                }
992
39415
            })
993
39346
            .for_each(|decl| self.set_property_from_declaration(&decl, origin, important_styles));
994
5210
    }
995
}
996

            
997
// Parses the value for the type `T` of the property out of the Parser, including `inherit` values.
998
57558
fn parse_input<'i, T>(input: &mut Parser<'i, '_>) -> Result<SpecifiedValue<T>, ParseError<'i>>
999
where
    T: Property + Clone + Default + Parse,
{
57558
    if input
57540
        .try_parse(|p| p.expect_ident_matching("inherit"))
57558
        .is_ok()
    {
30
        Ok(SpecifiedValue::Inherit)
    } else {
57528
        Parse::parse(input).map(SpecifiedValue::Specified)
    }
57558
}
#[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(
1
            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(
1
            StrokeWidth(length1),
1
        )));
1
        specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1
            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
    }
}