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, DeclarationListParser, ParseErrorKind, Parser, ParserInput, ToCss,
19 };
20 use markup5ever::{
21     expanded_name, local_name, namespace_url, ns, ExpandedName, LocalName, QualName,
22 };
23 use std::collections::HashSet;
24 
25 use crate::css::{DeclParser, Declaration, Origin};
26 use crate::error::*;
27 use crate::parsers::{Parse, ParseValue};
28 use crate::property_macros::Property;
29 use crate::transform::{Transform, TransformAttribute, TransformProperty};
30 use crate::xml::Attributes;
31 
32 // Re-export the actual properties so they are easy to find from a single place `properties::*`.
33 pub use crate::font_props::*;
34 pub use crate::property_defs::*;
35 
36 /// Representation of a single CSS property value.
37 ///
38 /// `Unspecified` is the `Default`; it means that the corresponding property is not present.
39 ///
40 /// `Inherit` means that the property is explicitly set to inherit
41 /// from the parent element.  This is useful for properties which the
42 /// SVG or CSS specs mandate that should not be inherited by default.
43 ///
44 /// `Specified` is a value given by the SVG or CSS stylesheet.  This will later be
45 /// resolved into part of a `ComputedValues` struct.
46 #[derive(Clone)]
47 pub enum SpecifiedValue<T>
48 where
49     T: Property + Clone + Default,
50 {
51     Unspecified,
52     Inherit,
53     Specified(T),
54 }
55 
56 impl<T> SpecifiedValue<T>
57 where
58     T: Property + Clone + Default,
59 {
compute(&self, src: &T, src_values: &ComputedValues) -> T60     pub fn compute(&self, src: &T, src_values: &ComputedValues) -> T {
61         let value: T = match *self {
62             SpecifiedValue::Unspecified => {
63                 if <T as Property>::inherits_automatically() {
64                     src.clone()
65                 } else {
66                     Default::default()
67                 }
68             }
69 
70             SpecifiedValue::Inherit => src.clone(),
71 
72             SpecifiedValue::Specified(ref v) => v.clone(),
73         };
74 
75         value.compute(src_values)
76     }
77 }
78 
79 /// Whether a property also has a presentation attribute.
80 ///
81 /// https://svgwg.org/svg2-draft/styling.html#PresentationAttributes
82 #[derive(PartialEq)]
83 enum PresentationAttr {
84     No,
85     Yes,
86 }
87 
88 /// How to parse a value, whether it comes from a property or from a presentation attribute
89 #[derive(PartialEq)]
90 pub enum ParseAs {
91     Property,
92     PresentationAttr,
93 }
94 
95 impl PropertyId {
as_u8(&self) -> u896     fn as_u8(&self) -> u8 {
97         *self as u8
98     }
99 
as_usize(&self) -> usize100     fn as_usize(&self) -> usize {
101         *self as usize
102     }
103 }
104 
105 /// Holds the specified values for the CSS properties of an element.
106 #[derive(Clone)]
107 pub struct SpecifiedValues {
108     indices: [u8; PropertyId::UnsetProperty as usize],
109     props: Vec<ParsedProperty>,
110 
111     transform: Option<Transform>,
112 }
113 
114 impl Default for SpecifiedValues {
default() -> Self115     fn default() -> Self {
116         SpecifiedValues {
117             // this many elements, with the same value
118             indices: [PropertyId::UnsetProperty.as_u8(); PropertyId::UnsetProperty as usize],
119             props: Vec::new(),
120             transform: None,
121         }
122     }
123 }
124 
125 impl ComputedValues {
126     // TODO for madds: this function will go away, to be replaced by the one generated
127     // automatically by the macros.
transform(&self) -> Transform128     pub fn transform(&self) -> Transform {
129         self.transform
130     }
131 
is_overflow(&self) -> bool132     pub fn is_overflow(&self) -> bool {
133         matches!(self.overflow(), Overflow::Auto | Overflow::Visible)
134     }
135 
136     /// Whether we should draw the element or skip both space allocation
137     /// and drawing.
138     /// https://www.w3.org/TR/SVG2/render.html#VisibilityControl
is_displayed(&self) -> bool139     pub fn is_displayed(&self) -> bool {
140         self.display() != Display::None
141     }
142 
143     /// Whether we should draw the element or allocate its space but
144     /// skip drawing.
145     /// https://www.w3.org/TR/SVG2/render.html#VisibilityControl
is_visible(&self) -> bool146     pub fn is_visible(&self) -> bool {
147         self.visibility() == Visibility::Visible
148     }
149 }
150 
151 /// Macro to generate all the machinery for properties.
152 ///
153 /// This generates the following:
154 ///
155 /// * `PropertyId`, an fieldless enum with simple values to identify all the properties.
156 /// * `ParsedProperty`, a variant enum for all the specified property values.
157 /// * `ComputedValue`, a variant enum for all the computed values.
158 /// * `parse_value`, the main function to parse a property or attribute value from user input.
159 ///
160 /// There is a lot of repetitive code, for example, because sometimes
161 /// we need to operate on `PropertyId::Foo`, `ParsedProperty::Foo` and
162 /// `ComputedValue::Foo` together.  This is why all this is done with a macro.
163 ///
164 /// See the only invocation of this macro to see how it is used; it is just
165 /// a declarative list of property names.
166 ///
167 /// **NOTE:** If you get a compiler error similar to this:
168 ///
169 /// ```text
170 /// 362 |         "mix-blend-mode"              => mix_blend_mode              : MixBlendMode,
171 ///     |         ^^^^^^^^^^^^^^^^ no rules expected this token in macro call
172 /// ```
173 ///
174 /// Then it may be that you put the name inside the `longhands` block, when it should be
175 /// inside the `longhands_not_supported_by_markup5ever` block.  This is because the
176 /// [`markup5ever`] crate does not have predefined names for every single property out
177 /// there; just the common ones.
178 ///
179 /// [`markup5ever`]: https://docs.rs/markup5ever
180 macro_rules! make_properties {
181     {
182         shorthands: {
183             $($short_str:tt => ( $short_presentation_attr:expr, $short_field:ident: $short_name:ident ),)*
184         }
185 
186         longhands: {
187             $($long_str:tt => ( $long_presentation_attr:expr, $long_field:ident: $long_name:ident ),)+
188         }
189 
190         // These are for when expanded_name!("" "foo") is not defined yet
191         // in markup5ever.  We create an ExpandedName by hand in that case.
192         longhands_not_supported_by_markup5ever: {
193             $($long_m5e_str:tt => ($long_m5e_presentation_attr:expr, $long_m5e_field:ident: $long_m5e_name:ident ),)+
194         }
195 
196         non_properties: {
197             $($nonprop_field:ident: $nonprop_name:ident,)+
198         }
199     }=> {
200         /// Used to match `ParsedProperty` to their discriminant
201         ///
202         /// The `PropertyId::UnsetProperty` can be used as a sentinel value, as
203         /// it does not match any `ParsedProperty` discriminant; it is really the
204         /// number of valid values in this enum.
205         #[repr(u8)]
206         #[derive(Copy, Clone, PartialEq)]
207         enum PropertyId {
208             $($short_name,)+
209             $($long_name,)+
210             $($long_m5e_name,)+
211             $($nonprop_name,)+
212 
213             UnsetProperty,
214         }
215 
216         impl PropertyId {
217             fn is_shorthand(self) -> bool {
218                 match self {
219                     $(PropertyId::$short_name => true,)+
220                     _ => false,
221                 }
222             }
223         }
224 
225         /// Embodies "which property is this" plus the property's value
226         #[derive(Clone)]
227         pub enum ParsedProperty {
228             // we put all the properties here; these are for SpecifiedValues
229             $($short_name(SpecifiedValue<$short_name>),)+
230             $($long_name(SpecifiedValue<$long_name>),)+
231             $($long_m5e_name(SpecifiedValue<$long_m5e_name>),)+
232             $($nonprop_name(SpecifiedValue<$nonprop_name>),)+
233         }
234 
235         enum ComputedValue {
236             $(
237                 $long_name($long_name),
238             )+
239 
240             $(
241                 $long_m5e_name($long_m5e_name),
242             )+
243 
244             $(
245                 $nonprop_name($nonprop_name),
246             )+
247         }
248 
249         /// Holds the computed values for the CSS properties of an element.
250         #[derive(Debug, Default, Clone)]
251         pub struct ComputedValues {
252             $(
253                 $long_field: $long_name,
254             )+
255 
256             $(
257                 $long_m5e_field: $long_m5e_name,
258             )+
259 
260             $(
261                 $nonprop_field: $nonprop_name,
262             )+
263 
264             transform: Transform,
265         }
266 
267         impl ParsedProperty {
268             fn get_property_id(&self) -> PropertyId {
269                 match *self {
270                     $(ParsedProperty::$long_name(_) => PropertyId::$long_name,)+
271                     $(ParsedProperty::$long_m5e_name(_) => PropertyId::$long_m5e_name,)+
272                     $(ParsedProperty::$short_name(_) => PropertyId::$short_name,)+
273                     $(ParsedProperty::$nonprop_name(_) => PropertyId::$nonprop_name,)+
274                 }
275             }
276 
277             fn unspecified(id: PropertyId) -> Self {
278                 use SpecifiedValue::Unspecified;
279 
280                 match id {
281                     $(PropertyId::$long_name => ParsedProperty::$long_name(Unspecified),)+
282                     $(PropertyId::$long_m5e_name => ParsedProperty::$long_m5e_name(Unspecified),)+
283                     $(PropertyId::$short_name => ParsedProperty::$short_name(Unspecified),)+
284                     $(PropertyId::$nonprop_name => ParsedProperty::$nonprop_name(Unspecified),)+
285 
286                     PropertyId::UnsetProperty => unreachable!(),
287                 }
288             }
289         }
290 
291         impl ComputedValues {
292             $(
293                 pub fn $long_field(&self) -> $long_name {
294                     if let ComputedValue::$long_name(v) = self.get_value(PropertyId::$long_name) {
295                         v
296                     } else {
297                         unreachable!();
298                     }
299                 }
300             )+
301 
302             $(
303                 pub fn $long_m5e_field(&self) -> $long_m5e_name {
304                     if let ComputedValue::$long_m5e_name(v) = self.get_value(PropertyId::$long_m5e_name) {
305                         v
306                     } else {
307                         unreachable!();
308                     }
309                 }
310             )+
311 
312             $(
313                 pub fn $nonprop_field(&self) -> $nonprop_name {
314                     if let ComputedValue::$nonprop_name(v) = self.get_value(PropertyId::$nonprop_name) {
315                         v
316                     } else {
317                         unreachable!();
318                     }
319                 }
320             )+
321 
322             fn set_value(&mut self, computed: ComputedValue) {
323                 match computed {
324                     $(ComputedValue::$long_name(v) => self.$long_field = v,)+
325                     $(ComputedValue::$long_m5e_name(v) => self.$long_m5e_field = v,)+
326                     $(ComputedValue::$nonprop_name(v) => self.$nonprop_field = v,)+
327                 }
328             }
329 
330             fn get_value(&self, id: PropertyId) -> ComputedValue {
331                 assert!(!id.is_shorthand());
332 
333                 match id {
334                     $(
335                         PropertyId::$long_name =>
336                             ComputedValue::$long_name(self.$long_field.clone()),
337                     )+
338                     $(
339                         PropertyId::$long_m5e_name =>
340                             ComputedValue::$long_m5e_name(self.$long_m5e_field.clone()),
341                     )+
342                     $(
343                         PropertyId::$nonprop_name =>
344                             ComputedValue::$nonprop_name(self.$nonprop_field.clone()),
345                     )+
346                     _ => unreachable!(),
347                 }
348             }
349         }
350 
351         /// Parses a value from either a style property or from an element's attribute.
352         pub fn parse_value<'i>(
353             prop_name: &QualName,
354             input: &mut Parser<'i, '_>,
355             parse_as: ParseAs,
356         ) -> Result<ParsedProperty, ParseError<'i>> {
357             match prop_name.expanded() {
358                 $(
359                     expanded_name!("", $long_str) if !(parse_as == ParseAs::PresentationAttr && $long_presentation_attr == PresentationAttr::No) => {
360                         Ok(ParsedProperty::$long_name(parse_input(input)?))
361                     }
362                 )+
363 
364                 $(
365                     e if e == ExpandedName {
366                         ns: &ns!(),
367                         local: &LocalName::from($long_m5e_str),
368                     } && !(parse_as == ParseAs::PresentationAttr && $long_m5e_presentation_attr == PresentationAttr::No) => {
369                         Ok(ParsedProperty::$long_m5e_name(parse_input(input)?))
370                     }
371                 )+
372 
373                 $(
374                     expanded_name!("", $short_str) if parse_as == ParseAs::Property => {
375                         // No shorthand has a presentation attribute.
376                         assert!($short_presentation_attr == PresentationAttr::No);
377 
378                         Ok(ParsedProperty::$short_name(parse_input(input)?))
379                     }
380                 )+
381 
382                 _ => {
383                     let loc = input.current_source_location();
384                     Err(loc.new_custom_error(ValueErrorKind::UnknownProperty))
385                 }
386             }
387         }
388     };
389 }
390 
391 #[rustfmt::skip]
392 make_properties! {
393     shorthands: {
394         // No shorthand has a presentation attribute.
395         "font"    => (PresentationAttr::No, font   : Font),
396         "marker"  => (PresentationAttr::No, marker : Marker),
397     }
398 
399     // longhands that are presentation attributes right now, but need to be turned into properties:
400     // "cx" - applies only to circle, ellipse
401     // "cy" - applies only to circle, ellipse
402     // "height" - applies only to foreignObject, image, rect, svg, symbol, use
403     // "width"  - applies only to foreignObject, image, rect, svg, symbol, use
404     // "x"      - applies only to foreignObject, image, rect, svg, symbol, use
405     // "y"      - applies only to foreignObject, image, rect, svg, symbol, use
406     // "r"      - applies only to circle
407     // "rx"     - applies only to ellipse, rect
408     // "ry"     - applies only to ellipse, rect
409     // "d"      - applies only to path
410 
411     longhands: {
412         // "alignment-baseline"       => (PresentationAttr::Yes, unimplemented),
413         "baseline-shift"              => (PresentationAttr::Yes, baseline_shift              : BaselineShift),
414         "clip-path"                   => (PresentationAttr::Yes, clip_path                   : ClipPath),
415         "clip-rule"                   => (PresentationAttr::Yes, clip_rule                   : ClipRule),
416         "color"                       => (PresentationAttr::Yes, color                       : Color),
417         // "color-interpolation"      => (PresentationAttr::Yes, unimplemented),
418         "color-interpolation-filters" => (PresentationAttr::Yes, color_interpolation_filters : ColorInterpolationFilters),
419         // "cursor"                   => (PresentationAttr::Yes, unimplemented),
420         "direction"                   => (PresentationAttr::Yes, direction                   : Direction),
421         "display"                     => (PresentationAttr::Yes, display                     : Display),
422         // "dominant-baseline"        => (PresentationAttr::Yes, unimplemented),
423         "enable-background"           => (PresentationAttr::Yes, enable_background           : EnableBackground),
424 
425         // "applies to any element except animation elements"
426         // https://www.w3.org/TR/SVG2/styling.html#PresentationAttributes
427         "fill"                        => (PresentationAttr::Yes, fill                        : Fill),
428 
429         "fill-opacity"                => (PresentationAttr::Yes, fill_opacity                : FillOpacity),
430         "fill-rule"                   => (PresentationAttr::Yes, fill_rule                   : FillRule),
431         "filter"                      => (PresentationAttr::Yes, filter                      : Filter),
432         "flood-color"                 => (PresentationAttr::Yes, flood_color                 : FloodColor),
433         "flood-opacity"               => (PresentationAttr::Yes, flood_opacity               : FloodOpacity),
434         "font-family"                 => (PresentationAttr::Yes, font_family                 : FontFamily),
435         "font-size"                   => (PresentationAttr::Yes, font_size                   : FontSize),
436         // "font-size-adjust"         => (PresentationAttr::Yes, unimplemented),
437         "font-stretch"                => (PresentationAttr::Yes, font_stretch                : FontStretch),
438         "font-style"                  => (PresentationAttr::Yes, font_style                  : FontStyle),
439         "font-variant"                => (PresentationAttr::Yes, font_variant                : FontVariant),
440         "font-weight"                 => (PresentationAttr::Yes, font_weight                 : FontWeight),
441 
442         // "glyph-orientation-horizontal" - obsolete, removed from SVG2
443 
444         // "glyph-orientation-vertical" - obsolete, now shorthand -
445         // https://svgwg.org/svg2-draft/text.html#GlyphOrientationVerticalProperty
446         // https://www.w3.org/TR/css-writing-modes-3/#propdef-glyph-orientation-vertical
447         //
448         // Note that even though CSS Writing Modes 3 turned glyph-orientation-vertical
449         // into a shorthand, SVG1.1 still makes it available as a presentation attribute.
450         // So, we put the property here, not in the shorthands, and deal with it as a
451         // special case in the text handling code.
452         "glyph-orientation-vertical"  => (PresentationAttr::Yes, glyph_orientation_vertical  : GlyphOrientationVertical),
453 
454         // "image-rendering"          => (PresentationAttr::Yes, unimplemented),
455         "letter-spacing"              => (PresentationAttr::Yes, letter_spacing              : LetterSpacing),
456         "lighting-color"              => (PresentationAttr::Yes, lighting_color              : LightingColor),
457         "marker-end"                  => (PresentationAttr::Yes, marker_end                  : MarkerEnd),
458         "marker-mid"                  => (PresentationAttr::Yes, marker_mid                  : MarkerMid),
459         "marker-start"                => (PresentationAttr::Yes, marker_start                : MarkerStart),
460         "mask"                        => (PresentationAttr::Yes, mask                        : Mask),
461         "opacity"                     => (PresentationAttr::Yes, opacity                     : Opacity),
462         "overflow"                    => (PresentationAttr::Yes, overflow                    : Overflow),
463         // "pointer-events"           => (PresentationAttr::Yes, unimplemented),
464         "shape-rendering"             => (PresentationAttr::Yes, shape_rendering             : ShapeRendering),
465         "stop-color"                  => (PresentationAttr::Yes, stop_color                  : StopColor),
466         "stop-opacity"                => (PresentationAttr::Yes, stop_opacity                : StopOpacity),
467         "stroke"                      => (PresentationAttr::Yes, stroke                      : Stroke),
468         "stroke-dasharray"            => (PresentationAttr::Yes, stroke_dasharray            : StrokeDasharray),
469         "stroke-dashoffset"           => (PresentationAttr::Yes, stroke_dashoffset           : StrokeDashoffset),
470         "stroke-linecap"              => (PresentationAttr::Yes, stroke_line_cap             : StrokeLinecap),
471         "stroke-linejoin"             => (PresentationAttr::Yes, stroke_line_join            : StrokeLinejoin),
472         "stroke-miterlimit"           => (PresentationAttr::Yes, stroke_miterlimit           : StrokeMiterlimit),
473         "stroke-opacity"              => (PresentationAttr::Yes, stroke_opacity              : StrokeOpacity),
474         "stroke-width"                => (PresentationAttr::Yes, stroke_width                : StrokeWidth),
475         "text-anchor"                 => (PresentationAttr::Yes, text_anchor                 : TextAnchor),
476         "text-decoration"             => (PresentationAttr::Yes, text_decoration             : TextDecoration),
477         // "text-overflow"            => (PresentationAttr::Yes, unimplemented),
478         "text-rendering"              => (PresentationAttr::Yes, text_rendering              : TextRendering),
479 
480         // "transform" - Special case as presentation attribute:
481         // The SVG1.1 "transform" attribute has a different grammar than the
482         // SVG2 "transform" property.  Here we define for the properties machinery,
483         // and it is handled specially as an attribute in parse_presentation_attributes().
484         "transform"                   => (PresentationAttr::No, transform_property           : TransformProperty),
485 
486         // "transform-box"            => (PresentationAttr::Yes, unimplemented),
487         // "transform-origin"         => (PresentationAttr::Yes, unimplemented),
488         "unicode-bidi"                => (PresentationAttr::Yes, unicode_bidi                : UnicodeBidi),
489         // "vector-effect"            => (PresentationAttr::Yes, unimplemented),
490         "visibility"                  => (PresentationAttr::Yes, visibility                  : Visibility),
491         // "white-space"              => (PresentationAttr::Yes, unimplemented),
492         // "word-spacing"             => (PresentationAttr::Yes, unimplemented),
493         "writing-mode"                => (PresentationAttr::Yes, writing_mode                : WritingMode),
494     }
495 
496     longhands_not_supported_by_markup5ever: {
497         "isolation"                   => (PresentationAttr::No,  isolation                   : Isolation),
498         "line-height"                 => (PresentationAttr::No,  line_height                 : LineHeight),
499         "mask-type"                   => (PresentationAttr::Yes, mask_type                   : MaskType),
500         "mix-blend-mode"              => (PresentationAttr::No,  mix_blend_mode              : MixBlendMode),
501         "paint-order"                 => (PresentationAttr::Yes, paint_order                 : PaintOrder),
502         "text-orientation"            => (PresentationAttr::No,  text_orientation            : TextOrientation),
503     }
504 
505     // These are not properties, but presentation attributes.  However,
506     // both xml:lang and xml:space *do* inherit.  We are abusing the
507     // property inheritance code for these XML-specific attributes.
508     non_properties: {
509         xml_lang: XmlLang,
510         xml_space: XmlSpace,
511     }
512 }
513 
514 impl SpecifiedValues {
property_index(&self, id: PropertyId) -> Option<usize>515     fn property_index(&self, id: PropertyId) -> Option<usize> {
516         let v = self.indices[id.as_usize()];
517 
518         if v == PropertyId::UnsetProperty.as_u8() {
519             None
520         } else {
521             Some(v as usize)
522         }
523     }
524 
set_property(&mut self, prop: &ParsedProperty, replace: bool)525     fn set_property(&mut self, prop: &ParsedProperty, replace: bool) {
526         let id = prop.get_property_id();
527         assert!(!id.is_shorthand());
528 
529         if let Some(index) = self.property_index(id) {
530             if replace {
531                 self.props[index] = prop.clone();
532             }
533         } else {
534             self.props.push(prop.clone());
535             let pos = self.props.len() - 1;
536             self.indices[id.as_usize()] = pos as u8;
537         }
538     }
539 
get_property(&self, id: PropertyId) -> ParsedProperty540     fn get_property(&self, id: PropertyId) -> ParsedProperty {
541         assert!(!id.is_shorthand());
542 
543         if let Some(index) = self.property_index(id) {
544             self.props[index].clone()
545         } else {
546             ParsedProperty::unspecified(id)
547         }
548     }
549 
set_property_expanding_shorthands(&mut self, prop: &ParsedProperty, replace: bool)550     fn set_property_expanding_shorthands(&mut self, prop: &ParsedProperty, replace: bool) {
551         match *prop {
552             ParsedProperty::Font(SpecifiedValue::Specified(ref f)) => {
553                 self.expand_font_shorthand(f, replace)
554             }
555             ParsedProperty::Marker(SpecifiedValue::Specified(ref m)) => {
556                 self.expand_marker_shorthand(m, replace)
557             }
558             ParsedProperty::Font(SpecifiedValue::Inherit) => {
559                 self.expand_font_shorthand_inherit(replace)
560             }
561             ParsedProperty::Marker(SpecifiedValue::Inherit) => {
562                 self.expand_marker_shorthand_inherit(replace)
563             }
564 
565             _ => self.set_property(prop, replace),
566         }
567     }
568 
expand_font_shorthand(&mut self, font: &Font, replace: bool)569     fn expand_font_shorthand(&mut self, font: &Font, replace: bool) {
570         let FontSpec {
571             style,
572             variant,
573             weight,
574             stretch,
575             size,
576             line_height,
577             family,
578         } = font.to_font_spec();
579 
580         self.set_property(
581             &ParsedProperty::FontStyle(SpecifiedValue::Specified(style)),
582             replace,
583         );
584         self.set_property(
585             &ParsedProperty::FontVariant(SpecifiedValue::Specified(variant)),
586             replace,
587         );
588         self.set_property(
589             &ParsedProperty::FontWeight(SpecifiedValue::Specified(weight)),
590             replace,
591         );
592         self.set_property(
593             &ParsedProperty::FontStretch(SpecifiedValue::Specified(stretch)),
594             replace,
595         );
596         self.set_property(
597             &ParsedProperty::FontSize(SpecifiedValue::Specified(size)),
598             replace,
599         );
600         self.set_property(
601             &ParsedProperty::LineHeight(SpecifiedValue::Specified(line_height)),
602             replace,
603         );
604         self.set_property(
605             &ParsedProperty::FontFamily(SpecifiedValue::Specified(family)),
606             replace,
607         );
608     }
609 
expand_marker_shorthand(&mut self, marker: &Marker, replace: bool)610     fn expand_marker_shorthand(&mut self, marker: &Marker, replace: bool) {
611         let Marker(v) = marker;
612 
613         self.set_property(
614             &ParsedProperty::MarkerStart(SpecifiedValue::Specified(MarkerStart(v.clone()))),
615             replace,
616         );
617         self.set_property(
618             &ParsedProperty::MarkerMid(SpecifiedValue::Specified(MarkerMid(v.clone()))),
619             replace,
620         );
621         self.set_property(
622             &ParsedProperty::MarkerEnd(SpecifiedValue::Specified(MarkerEnd(v.clone()))),
623             replace,
624         );
625     }
626 
expand_font_shorthand_inherit(&mut self, replace: bool)627     fn expand_font_shorthand_inherit(&mut self, replace: bool) {
628         self.set_property(&ParsedProperty::FontStyle(SpecifiedValue::Inherit), replace);
629         self.set_property(
630             &ParsedProperty::FontVariant(SpecifiedValue::Inherit),
631             replace,
632         );
633         self.set_property(
634             &ParsedProperty::FontWeight(SpecifiedValue::Inherit),
635             replace,
636         );
637         self.set_property(
638             &ParsedProperty::FontStretch(SpecifiedValue::Inherit),
639             replace,
640         );
641         self.set_property(&ParsedProperty::FontSize(SpecifiedValue::Inherit), replace);
642         self.set_property(
643             &ParsedProperty::LineHeight(SpecifiedValue::Inherit),
644             replace,
645         );
646         self.set_property(
647             &ParsedProperty::FontFamily(SpecifiedValue::Inherit),
648             replace,
649         );
650     }
651 
expand_marker_shorthand_inherit(&mut self, replace: bool)652     fn expand_marker_shorthand_inherit(&mut self, replace: bool) {
653         self.set_property(
654             &ParsedProperty::MarkerStart(SpecifiedValue::Inherit),
655             replace,
656         );
657         self.set_property(&ParsedProperty::MarkerMid(SpecifiedValue::Inherit), replace);
658         self.set_property(&ParsedProperty::MarkerEnd(SpecifiedValue::Inherit), replace);
659     }
660 
set_parsed_property(&mut self, prop: &ParsedProperty)661     pub fn set_parsed_property(&mut self, prop: &ParsedProperty) {
662         self.set_property_expanding_shorthands(prop, true);
663     }
664 
665     /* user agent property have less priority than presentation attributes */
set_parsed_property_user_agent(&mut self, prop: &ParsedProperty)666     pub fn set_parsed_property_user_agent(&mut self, prop: &ParsedProperty) {
667         self.set_property_expanding_shorthands(prop, false);
668     }
669 
to_computed_values(&self, computed: &mut ComputedValues)670     pub fn to_computed_values(&self, computed: &mut ComputedValues) {
671         macro_rules! compute {
672             ($name:ident, $field:ident) => {{
673                 // This extra block --------^
674                 // is so that prop_val will be dropped within the macro invocation;
675                 // otherwise all the temporary values cause this function to use
676                 // an unreasonably large amount of stack space.
677                 let prop_val = self.get_property(PropertyId::$name);
678                 if let ParsedProperty::$name(s) = prop_val {
679                     computed.set_value(ComputedValue::$name(
680                         s.compute(&computed.$field(), computed),
681                     ));
682                 } else {
683                     unreachable!();
684                 }
685             }};
686         }
687 
688         // First, compute font_size.  It needs to be done before everything
689         // else, so that properties that depend on its computed value
690         // will be able to use it.  For example, baseline-shift
691         // depends on font-size.
692 
693         compute!(FontSize, font_size);
694 
695         // Then, do all the other properties.
696 
697         compute!(BaselineShift, baseline_shift);
698         compute!(ClipPath, clip_path);
699         compute!(ClipRule, clip_rule);
700         compute!(Color, color);
701         compute!(ColorInterpolationFilters, color_interpolation_filters);
702         compute!(Direction, direction);
703         compute!(Display, display);
704         compute!(EnableBackground, enable_background);
705         compute!(Fill, fill);
706         compute!(FillOpacity, fill_opacity);
707         compute!(FillRule, fill_rule);
708         compute!(Filter, filter);
709         compute!(FloodColor, flood_color);
710         compute!(FloodOpacity, flood_opacity);
711         compute!(FontFamily, font_family);
712         compute!(FontStretch, font_stretch);
713         compute!(FontStyle, font_style);
714         compute!(FontVariant, font_variant);
715         compute!(FontWeight, font_weight);
716         compute!(GlyphOrientationVertical, glyph_orientation_vertical);
717         compute!(Isolation, isolation);
718         compute!(LetterSpacing, letter_spacing);
719         compute!(LightingColor, lighting_color);
720         compute!(MarkerEnd, marker_end);
721         compute!(MarkerMid, marker_mid);
722         compute!(MarkerStart, marker_start);
723         compute!(Mask, mask);
724         compute!(MaskType, mask_type);
725         compute!(MixBlendMode, mix_blend_mode);
726         compute!(Opacity, opacity);
727         compute!(Overflow, overflow);
728         compute!(PaintOrder, paint_order);
729         compute!(ShapeRendering, shape_rendering);
730         compute!(StopColor, stop_color);
731         compute!(StopOpacity, stop_opacity);
732         compute!(Stroke, stroke);
733         compute!(StrokeDasharray, stroke_dasharray);
734         compute!(StrokeDashoffset, stroke_dashoffset);
735         compute!(StrokeLinecap, stroke_line_cap);
736         compute!(StrokeLinejoin, stroke_line_join);
737         compute!(StrokeOpacity, stroke_opacity);
738         compute!(StrokeMiterlimit, stroke_miterlimit);
739         compute!(StrokeWidth, stroke_width);
740         compute!(TextAnchor, text_anchor);
741         compute!(TextDecoration, text_decoration);
742         compute!(TextOrientation, text_orientation);
743         compute!(TextRendering, text_rendering);
744         compute!(TransformProperty, transform_property);
745         compute!(UnicodeBidi, unicode_bidi);
746         compute!(Visibility, visibility);
747         compute!(WritingMode, writing_mode);
748         compute!(XmlSpace, xml_space);
749         compute!(XmlLang, xml_lang);
750 
751         computed.transform = self.transform.unwrap_or_else(|| {
752             match self.get_property(PropertyId::TransformProperty) {
753                 ParsedProperty::TransformProperty(SpecifiedValue::Specified(ref t)) => {
754                     t.to_transform()
755                 }
756                 _ => Transform::identity(),
757             }
758         });
759     }
760 
761     /// This is a somewhat egregious hack to allow xml:lang to be stored as a presentational
762     /// attribute. Presentational attributes can often be influenced by stylesheets,
763     /// so they're cascaded after selector matching is done, but xml:lang can be queried by
764     /// CSS selectors, so they need to be cascaded *first*.
inherit_xml_lang( &self, computed: &mut ComputedValues, parent: Option<crate::node::Node>, )765     pub fn inherit_xml_lang(
766         &self,
767         computed: &mut ComputedValues,
768         parent: Option<crate::node::Node>,
769     ) {
770         use crate::node::NodeBorrow;
771         let prop_val = self.get_property(PropertyId::XmlLang);
772         if let ParsedProperty::XmlLang(s) = prop_val {
773             if let Some(parent) = parent {
774                 computed.set_value(ComputedValue::XmlLang(
775                     parent.borrow_element().get_computed_values().xml_lang(),
776                 ));
777             }
778             computed.set_value(ComputedValue::XmlLang(
779                 s.compute(&computed.xml_lang(), computed),
780             ));
781         } else {
782             unreachable!();
783         }
784     }
785 
is_overflow(&self) -> bool786     pub fn is_overflow(&self) -> bool {
787         if let Some(overflow_index) = self.property_index(PropertyId::Overflow) {
788             match self.props[overflow_index] {
789                 ParsedProperty::Overflow(SpecifiedValue::Specified(Overflow::Auto)) => true,
790                 ParsedProperty::Overflow(SpecifiedValue::Specified(Overflow::Visible)) => true,
791                 ParsedProperty::Overflow(_) => false,
792                 _ => unreachable!(),
793             }
794         } else {
795             false
796         }
797     }
798 
parse_one_presentation_attribute(&mut self, attr: QualName, value: &str)799     fn parse_one_presentation_attribute(&mut self, attr: QualName, value: &str) {
800         let mut input = ParserInput::new(value);
801         let mut parser = Parser::new(&mut input);
802 
803         match parse_value(&attr, &mut parser, ParseAs::PresentationAttr) {
804             Ok(prop) => {
805                 if parser.expect_exhausted().is_ok() {
806                     self.set_parsed_property(&prop);
807                 } else {
808                     rsvg_log!(
809                         "(ignoring invalid presentation attribute {:?}\n    value=\"{}\")\n",
810                         attr.expanded(),
811                         value,
812                     );
813                 }
814             }
815 
816             // not a presentation attribute; just ignore it
817             Err(ParseError {
818                 kind: ParseErrorKind::Custom(ValueErrorKind::UnknownProperty),
819                 ..
820             }) => (),
821 
822             // https://www.w3.org/TR/CSS2/syndata.html#unsupported-values
823             // For all the following cases, ignore illegal values; don't set the whole node to
824             // be in error in that case.
825             Err(ParseError {
826                 kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)),
827                 ..
828             }) => {
829                 let mut tok = String::new();
830 
831                 t.to_css(&mut tok).unwrap(); // FIXME: what do we do with a fmt::Error?
832                 rsvg_log!(
833                     "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    \
834                      unexpected token '{}')",
835                     attr.expanded(),
836                     value,
837                     tok,
838                 );
839             }
840 
841             Err(ParseError {
842                 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
843                 ..
844             }) => {
845                 rsvg_log!(
846                     "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    \
847                      unexpected end of input)",
848                     attr.expanded(),
849                     value,
850                 );
851             }
852 
853             Err(ParseError {
854                 kind: ParseErrorKind::Basic(_),
855                 ..
856             }) => {
857                 rsvg_log!(
858                     "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    \
859                      unexpected error)",
860                     attr.expanded(),
861                     value,
862                 );
863             }
864 
865             Err(ParseError {
866                 kind: ParseErrorKind::Custom(ref v),
867                 ..
868             }) => {
869                 rsvg_log!(
870                     "(ignoring invalid presentation attribute {:?}\n    value=\"{}\"\n    {})",
871                     attr.expanded(),
872                     value,
873                     v
874                 );
875             }
876         }
877     }
878 
parse_presentation_attributes( &mut self, attrs: &Attributes, ) -> Result<(), ElementError>879     pub fn parse_presentation_attributes(
880         &mut self,
881         attrs: &Attributes,
882     ) -> Result<(), ElementError> {
883         for (attr, value) in attrs.iter() {
884             match attr.expanded() {
885                 expanded_name!("", "transform") => {
886                     // FIXME: we parse the transform attribute here because we don't yet have
887                     // a better way to distinguish attributes whose values have different
888                     // grammars than properties.
889                     let transform_attr = TransformAttribute::parse_str(value)
890                         .unwrap_or_else(|_| TransformAttribute::default());
891                     self.transform = Some(transform_attr.to_transform());
892                 }
893 
894                 expanded_name!(xml "lang") => {
895                     // xml:lang is a non-presentation attribute and as such cannot have the
896                     // "inherit" value.  So, we don't call parse_one_presentation_attribute()
897                     // for it, but rather call its parser directly.
898                     self.set_parsed_property(&ParsedProperty::XmlLang(SpecifiedValue::Specified(
899                         attr.parse(value)?,
900                     )));
901                 }
902 
903                 expanded_name!(xml "space") => {
904                     // xml:space is a non-presentation attribute and as such cannot have the
905                     // "inherit" value.  So, we don't call parse_one_presentation_attribute()
906                     // for it, but rather call its parser directly.
907                     self.set_parsed_property(&ParsedProperty::XmlSpace(SpecifiedValue::Specified(
908                         attr.parse(value)?,
909                     )));
910                 }
911 
912                 _ => self.parse_one_presentation_attribute(attr, value),
913             }
914         }
915 
916         Ok(())
917     }
918 
set_property_from_declaration( &mut self, declaration: &Declaration, origin: Origin, important_styles: &mut HashSet<QualName>, )919     pub fn set_property_from_declaration(
920         &mut self,
921         declaration: &Declaration,
922         origin: Origin,
923         important_styles: &mut HashSet<QualName>,
924     ) {
925         if !declaration.important && important_styles.contains(&declaration.prop_name) {
926             return;
927         }
928 
929         if declaration.important {
930             important_styles.insert(declaration.prop_name.clone());
931         }
932 
933         if origin == Origin::UserAgent {
934             self.set_parsed_property_user_agent(&declaration.property);
935         } else {
936             self.set_parsed_property(&declaration.property);
937         }
938     }
939 
parse_style_declarations( &mut self, declarations: &str, origin: Origin, important_styles: &mut HashSet<QualName>, ) -> Result<(), ElementError>940     pub fn parse_style_declarations(
941         &mut self,
942         declarations: &str,
943         origin: Origin,
944         important_styles: &mut HashSet<QualName>,
945     ) -> Result<(), ElementError> {
946         let mut input = ParserInput::new(declarations);
947         let mut parser = Parser::new(&mut input);
948 
949         DeclarationListParser::new(&mut parser, DeclParser)
950             .filter_map(|r| match r {
951                 Ok(decl) => Some(decl),
952                 Err(e) => {
953                     rsvg_log!("Invalid declaration; ignoring: {:?}", e);
954                     None
955                 }
956             })
957             .for_each(|decl| self.set_property_from_declaration(&decl, origin, important_styles));
958 
959         Ok(())
960     }
961 }
962 
963 // Parses the value for the type `T` of the property out of the Parser, including `inherit` values.
parse_input<'i, T>(input: &mut Parser<'i, '_>) -> Result<SpecifiedValue<T>, ParseError<'i>> where T: Property + Clone + Default + Parse,964 fn parse_input<'i, T>(input: &mut Parser<'i, '_>) -> Result<SpecifiedValue<T>, ParseError<'i>>
965 where
966     T: Property + Clone + Default + Parse,
967 {
968     if input
969         .try_parse(|p| p.expect_ident_matching("inherit"))
970         .is_ok()
971     {
972         Ok(SpecifiedValue::Inherit)
973     } else {
974         Parse::parse(input).map(SpecifiedValue::Specified)
975     }
976 }
977 
978 #[cfg(test)]
979 mod tests {
980     use super::*;
981     use crate::iri::Iri;
982     use crate::length::*;
983 
984     #[test]
empty_values_computes_to_defaults()985     fn empty_values_computes_to_defaults() {
986         let specified = SpecifiedValues::default();
987 
988         let mut computed = ComputedValues::default();
989         specified.to_computed_values(&mut computed);
990 
991         assert_eq!(computed.stroke_width(), StrokeWidth::default());
992     }
993 
994     #[test]
set_one_property()995     fn set_one_property() {
996         let length = Length::<Both>::new(42.0, LengthUnit::Px);
997 
998         let mut specified = SpecifiedValues::default();
999         specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1000             StrokeWidth(length),
1001         )));
1002 
1003         let mut computed = ComputedValues::default();
1004         specified.to_computed_values(&mut computed);
1005 
1006         assert_eq!(computed.stroke_width(), StrokeWidth(length));
1007     }
1008 
1009     #[test]
replace_existing_property()1010     fn replace_existing_property() {
1011         let length1 = Length::<Both>::new(42.0, LengthUnit::Px);
1012         let length2 = Length::<Both>::new(42.0, LengthUnit::Px);
1013 
1014         let mut specified = SpecifiedValues::default();
1015 
1016         specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1017             StrokeWidth(length1),
1018         )));
1019 
1020         specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1021             StrokeWidth(length2),
1022         )));
1023 
1024         let mut computed = ComputedValues::default();
1025         specified.to_computed_values(&mut computed);
1026 
1027         assert_eq!(computed.stroke_width(), StrokeWidth(length2));
1028     }
1029 
1030     #[test]
expands_marker_shorthand()1031     fn expands_marker_shorthand() {
1032         let mut specified = SpecifiedValues::default();
1033         let iri = Iri::parse_str("url(#foo)").unwrap();
1034 
1035         let marker = Marker(iri.clone());
1036         specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker)));
1037 
1038         let mut computed = ComputedValues::default();
1039         specified.to_computed_values(&mut computed);
1040 
1041         assert_eq!(computed.marker_start(), MarkerStart(iri.clone()));
1042         assert_eq!(computed.marker_mid(), MarkerMid(iri.clone()));
1043         assert_eq!(computed.marker_end(), MarkerEnd(iri.clone()));
1044     }
1045 
1046     #[test]
replaces_marker_shorthand()1047     fn replaces_marker_shorthand() {
1048         let mut specified = SpecifiedValues::default();
1049         let iri1 = Iri::parse_str("url(#foo)").unwrap();
1050         let iri2 = Iri::None;
1051 
1052         let marker1 = Marker(iri1.clone());
1053         specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker1)));
1054 
1055         let marker2 = Marker(iri2.clone());
1056         specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker2)));
1057 
1058         let mut computed = ComputedValues::default();
1059         specified.to_computed_values(&mut computed);
1060 
1061         assert_eq!(computed.marker_start(), MarkerStart(iri2.clone()));
1062         assert_eq!(computed.marker_mid(), MarkerMid(iri2.clone()));
1063         assert_eq!(computed.marker_end(), MarkerEnd(iri2.clone()));
1064     }
1065 
1066     #[test]
computes_property_that_does_not_inherit_automatically()1067     fn computes_property_that_does_not_inherit_automatically() {
1068         assert_eq!(<Opacity as Property>::inherits_automatically(), false);
1069 
1070         let half_opacity = Opacity::parse_str("0.5").unwrap();
1071 
1072         // first level, as specified with opacity
1073 
1074         let mut with_opacity = SpecifiedValues::default();
1075         with_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Specified(
1076             half_opacity.clone(),
1077         )));
1078 
1079         let mut computed_0_5 = ComputedValues::default();
1080         with_opacity.to_computed_values(&mut computed_0_5);
1081 
1082         assert_eq!(computed_0_5.opacity(), half_opacity.clone());
1083 
1084         // second level, no opacity specified, and it doesn't inherit
1085 
1086         let without_opacity = SpecifiedValues::default();
1087 
1088         let mut computed = computed_0_5.clone();
1089         without_opacity.to_computed_values(&mut computed);
1090 
1091         assert_eq!(computed.opacity(), Opacity::default());
1092 
1093         // another at second level, opacity set to explicitly inherit
1094 
1095         let mut with_inherit_opacity = SpecifiedValues::default();
1096         with_inherit_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Inherit));
1097 
1098         let mut computed = computed_0_5.clone();
1099         with_inherit_opacity.to_computed_values(&mut computed);
1100 
1101         assert_eq!(computed.opacity(), half_opacity.clone());
1102     }
1103 
1104     #[test]
empty_style_attribute_parses_ok()1105     fn empty_style_attribute_parses_ok() {
1106         let mut specified = SpecifiedValues::default();
1107 
1108         assert!(specified
1109             .parse_style_declarations("", Origin::Author, &mut HashSet::new())
1110             .is_ok())
1111     }
1112 }
1113