1use cssparser::{
18 self, BasicParseErrorKind, ParseErrorKind, Parser, ParserInput, RuleBodyParser, ToCss,
19};
20use markup5ever::{expanded_name, local_name, ns, ExpandedName, LocalName, QualName};
21use std::collections::HashSet;
22
23#[cfg(doc)]
24use crate::make_property;
25
26use crate::css::{DeclParser, Declaration, Origin, RuleBodyItem};
27use crate::error::*;
28use crate::parsers::{Parse, ParseValue};
29use crate::property_macros::Property;
30use crate::rsvg_log;
31use crate::session::Session;
32use crate::transform::{Transform, TransformAttribute, TransformProperty};
33use crate::xml::Attributes;
34
35pub use crate::font_props::*;
37pub use crate::property_defs::*;
38
39#[derive(Clone)]
50pub enum SpecifiedValue<T>
51where
52 T: Property + Clone + Default,
53{
54 Unspecified,
55 Inherit,
56 Specified(T),
57}
58
59impl<T> SpecifiedValue<T>
60where
61 T: Property + Clone + Default,
62{
63 pub fn compute(&self, src: &T, src_values: &ComputedValues) -> T {
64 let value: T = match *self {
65 SpecifiedValue::Unspecified => {
66 if <T as Property>::inherits_automatically() {
67 src.clone()
68 } else {
69 Default::default()
70 }
71 }
72
73 SpecifiedValue::Inherit => src.clone(),
74
75 SpecifiedValue::Specified(ref v) => v.clone(),
76 };
77
78 value.compute(src_values)
79 }
80}
81
82#[derive(PartialEq)]
86enum PresentationAttr {
87 No,
88 Yes,
89}
90
91#[derive(PartialEq)]
93pub enum ParseAs {
94 Property,
95 PresentationAttr,
96}
97
98impl PropertyId {
99 fn as_u8(&self) -> u8 {
100 *self as u8
101 }
102
103 fn as_usize(&self) -> usize {
104 *self as usize
105 }
106}
107
108#[derive(Clone)]
110pub struct SpecifiedValues {
111 indices: [u8; PropertyId::UnsetProperty as usize],
112 props: Vec<ParsedProperty>,
113
114 transform: Option<Transform>,
115}
116
117impl Default for SpecifiedValues {
118 fn default() -> Self {
119 SpecifiedValues {
120 indices: [PropertyId::UnsetProperty.as_u8(); PropertyId::UnsetProperty as usize],
122 props: Vec::new(),
123 transform: None,
124 }
125 }
126}
127
128impl ComputedValues {
129 pub fn transform(&self) -> Transform {
132 self.transform
133 }
134
135 pub fn is_overflow(&self) -> bool {
136 matches!(self.overflow(), Overflow::Auto | Overflow::Visible)
137 }
138
139 pub fn is_displayed(&self) -> bool {
143 self.display() != Display::None
144 }
145
146 pub fn is_visible(&self) -> bool {
150 self.visibility() == Visibility::Visible
151 }
152}
153
154macro_rules! make_properties {
184 {
185 shorthands: {
186 $($short_str:tt => ( $short_presentation_attr:expr, $short_field:ident: $short_name:ident ),)*
187 }
188
189 longhands: {
190 $($long_str:tt => ( $long_presentation_attr:expr, $long_field:ident: $long_name:ident ),)+
191 }
192
193 longhands_not_supported_by_markup5ever: {
196 $($long_m5e_str:tt => ($long_m5e_presentation_attr:expr, $long_m5e_field:ident: $long_m5e_name:ident ),)+
197 }
198
199 non_properties: {
200 $($nonprop_field:ident: $nonprop_name:ident,)+
201 }
202 }=> {
203 #[repr(u8)]
209 #[derive(Copy, Clone, PartialEq)]
210 enum PropertyId {
211 $($short_name,)+
212 $($long_name,)+
213 $($long_m5e_name,)+
214 $($nonprop_name,)+
215
216 UnsetProperty,
217 }
218
219 impl PropertyId {
220 fn is_shorthand(self) -> bool {
221 match self {
222 $(PropertyId::$short_name => true,)+
223 _ => false,
224 }
225 }
226 }
227
228 #[derive(Clone)]
230 pub enum ParsedProperty {
231 $($short_name(SpecifiedValue<$short_name>),)+
233 $($long_name(SpecifiedValue<$long_name>),)+
234 $($long_m5e_name(SpecifiedValue<$long_m5e_name>),)+
235 $($nonprop_name(SpecifiedValue<$nonprop_name>),)+
236 }
237
238 enum ComputedValue {
239 $(
240 $long_name($long_name),
241 )+
242
243 $(
244 $long_m5e_name($long_m5e_name),
245 )+
246
247 $(
248 $nonprop_name($nonprop_name),
249 )+
250 }
251
252 #[derive(Debug, Default, Clone)]
254 pub struct ComputedValues {
255 $(
256 $long_field: $long_name,
257 )+
258
259 $(
260 $long_m5e_field: $long_m5e_name,
261 )+
262
263 $(
264 $nonprop_field: $nonprop_name,
265 )+
266
267 transform: Transform,
268 }
269
270 impl ParsedProperty {
271 fn get_property_id(&self) -> PropertyId {
272 match *self {
273 $(ParsedProperty::$long_name(_) => PropertyId::$long_name,)+
274 $(ParsedProperty::$long_m5e_name(_) => PropertyId::$long_m5e_name,)+
275 $(ParsedProperty::$short_name(_) => PropertyId::$short_name,)+
276 $(ParsedProperty::$nonprop_name(_) => PropertyId::$nonprop_name,)+
277 }
278 }
279
280 fn unspecified(id: PropertyId) -> Self {
281 use SpecifiedValue::Unspecified;
282
283 match id {
284 $(PropertyId::$long_name => ParsedProperty::$long_name(Unspecified),)+
285 $(PropertyId::$long_m5e_name => ParsedProperty::$long_m5e_name(Unspecified),)+
286 $(PropertyId::$short_name => ParsedProperty::$short_name(Unspecified),)+
287 $(PropertyId::$nonprop_name => ParsedProperty::$nonprop_name(Unspecified),)+
288
289 PropertyId::UnsetProperty => unreachable!(),
290 }
291 }
292 }
293
294 impl ComputedValues {
295 $(
296 pub fn $long_field(&self) -> $long_name {
297 if let ComputedValue::$long_name(v) = self.get_value(PropertyId::$long_name) {
298 v
299 } else {
300 unreachable!();
301 }
302 }
303 )+
304
305 $(
306 pub fn $long_m5e_field(&self) -> $long_m5e_name {
307 if let ComputedValue::$long_m5e_name(v) = self.get_value(PropertyId::$long_m5e_name) {
308 v
309 } else {
310 unreachable!();
311 }
312 }
313 )+
314
315 $(
316 pub fn $nonprop_field(&self) -> $nonprop_name {
317 if let ComputedValue::$nonprop_name(v) = self.get_value(PropertyId::$nonprop_name) {
318 v
319 } else {
320 unreachable!();
321 }
322 }
323 )+
324
325 fn set_value(&mut self, computed: ComputedValue) {
326 match computed {
327 $(ComputedValue::$long_name(v) => self.$long_field = v,)+
328 $(ComputedValue::$long_m5e_name(v) => self.$long_m5e_field = v,)+
329 $(ComputedValue::$nonprop_name(v) => self.$nonprop_field = v,)+
330 }
331 }
332
333 fn get_value(&self, id: PropertyId) -> ComputedValue {
334 assert!(!id.is_shorthand());
335
336 match id {
337 $(
338 PropertyId::$long_name =>
339 ComputedValue::$long_name(self.$long_field.clone()),
340 )+
341 $(
342 PropertyId::$long_m5e_name =>
343 ComputedValue::$long_m5e_name(self.$long_m5e_field.clone()),
344 )+
345 $(
346 PropertyId::$nonprop_name =>
347 ComputedValue::$nonprop_name(self.$nonprop_field.clone()),
348 )+
349 _ => unreachable!(),
350 }
351 }
352 }
353
354 pub fn parse_value<'i>(
356 prop_name: &QualName,
357 input: &mut Parser<'i, '_>,
358 parse_as: ParseAs,
359 ) -> Result<ParsedProperty, ParseError<'i>> {
360 match prop_name.expanded() {
361 $(
362 expanded_name!("", $long_str) if !(parse_as == ParseAs::PresentationAttr && $long_presentation_attr == PresentationAttr::No) => {
363 Ok(ParsedProperty::$long_name(parse_input(input)?))
364 }
365 )+
366
367 $(
368 e if e == ExpandedName {
369 ns: &ns!(),
370 local: &LocalName::from($long_m5e_str),
371 } && !(parse_as == ParseAs::PresentationAttr && $long_m5e_presentation_attr == PresentationAttr::No) => {
372 Ok(ParsedProperty::$long_m5e_name(parse_input(input)?))
373 }
374 )+
375
376 $(
377 expanded_name!("", $short_str) if parse_as == ParseAs::Property => {
378 assert!($short_presentation_attr == PresentationAttr::No);
380
381 Ok(ParsedProperty::$short_name(parse_input(input)?))
382 }
383 )+
384
385 _ => {
386 let loc = input.current_source_location();
387 Err(loc.new_custom_error(ValueErrorKind::UnknownProperty))
388 }
389 }
390 }
391 };
392}
393
394#[rustfmt::skip]
395make_properties! {
396 shorthands: {
397 "font" => (PresentationAttr::No, font : Font),
399 "marker" => (PresentationAttr::No, marker : Marker),
400 }
401
402 longhands: {
406 "baseline-shift" => (PresentationAttr::Yes, baseline_shift : BaselineShift),
408 "clip-path" => (PresentationAttr::Yes, clip_path : ClipPath),
409 "clip-rule" => (PresentationAttr::Yes, clip_rule : ClipRule),
410 "color" => (PresentationAttr::Yes, color : Color),
411 "color-interpolation-filters" => (PresentationAttr::Yes, color_interpolation_filters : ColorInterpolationFilters),
413 "cx" => (PresentationAttr::Yes, cx: CX),
415 "cy" => (PresentationAttr::Yes, cy: CY),
416 "direction" => (PresentationAttr::Yes, direction : Direction),
417 "display" => (PresentationAttr::Yes, display : Display),
418 "dominant-baseline" => (PresentationAttr::Yes, dominant_baseline : DominantBaseline),
419 "enable-background" => (PresentationAttr::Yes, enable_background : EnableBackground),
420
421 "fill" => (PresentationAttr::Yes, fill : Fill),
424
425 "fill-opacity" => (PresentationAttr::Yes, fill_opacity : FillOpacity),
426 "fill-rule" => (PresentationAttr::Yes, fill_rule : FillRule),
427 "filter" => (PresentationAttr::Yes, filter : Filter),
428 "flood-color" => (PresentationAttr::Yes, flood_color : FloodColor),
429 "flood-opacity" => (PresentationAttr::Yes, flood_opacity : FloodOpacity),
430 "font-family" => (PresentationAttr::Yes, font_family : FontFamily),
431 "font-size" => (PresentationAttr::Yes, font_size : FontSize),
432 "font-stretch" => (PresentationAttr::Yes, font_stretch : FontStretch),
434 "font-style" => (PresentationAttr::Yes, font_style : FontStyle),
435 "font-variant" => (PresentationAttr::Yes, font_variant : FontVariant),
436 "font-weight" => (PresentationAttr::Yes, font_weight : FontWeight),
437
438 "glyph-orientation-vertical" => (PresentationAttr::Yes, glyph_orientation_vertical : GlyphOrientationVertical),
449 "height" => (PresentationAttr::Yes, height: Height),
450
451 "image-rendering" => (PresentationAttr::Yes, image_rendering : ImageRendering),
452 "letter-spacing" => (PresentationAttr::Yes, letter_spacing : LetterSpacing),
453 "lighting-color" => (PresentationAttr::Yes, lighting_color : LightingColor),
454 "marker-end" => (PresentationAttr::Yes, marker_end : MarkerEnd),
455 "marker-mid" => (PresentationAttr::Yes, marker_mid : MarkerMid),
456 "marker-start" => (PresentationAttr::Yes, marker_start : MarkerStart),
457 "mask" => (PresentationAttr::Yes, mask : Mask),
458 "opacity" => (PresentationAttr::Yes, opacity : Opacity),
459 "overflow" => (PresentationAttr::Yes, overflow : Overflow),
460 "r" => (PresentationAttr::Yes, r: R),
462 "rx" => (PresentationAttr::Yes, rx: RX),
463 "ry" => (PresentationAttr::Yes, ry: RY),
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-rendering" => (PresentationAttr::Yes, text_rendering : TextRendering),
479
480 "transform" => (PresentationAttr::No, transform_property : TransformProperty),
485
486 "unicode-bidi" => (PresentationAttr::Yes, unicode_bidi : UnicodeBidi),
489 "visibility" => (PresentationAttr::Yes, visibility : Visibility),
490 "width" => (PresentationAttr::Yes, width: Width),
492 "writing-mode" => (PresentationAttr::Yes, writing_mode : WritingMode),
493 "x" => (PresentationAttr::Yes, x: X),
494 "y" => (PresentationAttr::Yes, y: Y),
495 }
496
497 longhands_not_supported_by_markup5ever: {
498 "isolation" => (PresentationAttr::No, isolation : Isolation),
499 "line-height" => (PresentationAttr::No, line_height : LineHeight),
500 "mask-type" => (PresentationAttr::Yes, mask_type : MaskType),
501 "mix-blend-mode" => (PresentationAttr::No, mix_blend_mode : MixBlendMode),
502 "paint-order" => (PresentationAttr::Yes, paint_order : PaintOrder),
503 "text-orientation" => (PresentationAttr::No, text_orientation : TextOrientation),
504 "vector-effect" => (PresentationAttr::Yes, vector_effect : VectorEffect),
505 "white-space" => (PresentationAttr::Yes, white_space : WhiteSpace),
506 }
507
508 non_properties: {
512 xml_lang: XmlLang,
513 xml_space: XmlSpace,
514 }
515}
516
517impl SpecifiedValues {
518 fn property_index(&self, id: PropertyId) -> Option<usize> {
519 let v = self.indices[id.as_usize()];
520
521 if v == PropertyId::UnsetProperty.as_u8() {
522 None
523 } else {
524 Some(v as usize)
525 }
526 }
527
528 fn set_property(&mut self, prop: &ParsedProperty, replace: bool) {
529 let id = prop.get_property_id();
530 assert!(!id.is_shorthand());
531
532 if let Some(index) = self.property_index(id) {
533 if replace {
534 self.props[index] = prop.clone();
535 }
536 } else {
537 self.props.push(prop.clone());
538 let pos = self.props.len() - 1;
539 self.indices[id.as_usize()] = pos as u8;
540 }
541 }
542
543 fn get_property(&self, id: PropertyId) -> ParsedProperty {
544 assert!(!id.is_shorthand());
545
546 if let Some(index) = self.property_index(id) {
547 self.props[index].clone()
548 } else {
549 ParsedProperty::unspecified(id)
550 }
551 }
552
553 fn set_property_expanding_shorthands(&mut self, prop: &ParsedProperty, replace: bool) {
554 match *prop {
555 ParsedProperty::Font(SpecifiedValue::Specified(ref f)) => {
556 self.expand_font_shorthand(f, replace)
557 }
558 ParsedProperty::Marker(SpecifiedValue::Specified(ref m)) => {
559 self.expand_marker_shorthand(m, replace)
560 }
561 ParsedProperty::Font(SpecifiedValue::Inherit) => {
562 self.expand_font_shorthand_inherit(replace)
563 }
564 ParsedProperty::Marker(SpecifiedValue::Inherit) => {
565 self.expand_marker_shorthand_inherit(replace)
566 }
567
568 _ => self.set_property(prop, replace),
569 }
570 }
571
572 fn expand_font_shorthand(&mut self, font: &Font, replace: bool) {
573 let FontSpec {
574 style,
575 variant,
576 weight,
577 stretch,
578 size,
579 line_height,
580 family,
581 } = font.to_font_spec();
582
583 self.set_property(
584 &ParsedProperty::FontStyle(SpecifiedValue::Specified(style)),
585 replace,
586 );
587 self.set_property(
588 &ParsedProperty::FontVariant(SpecifiedValue::Specified(variant)),
589 replace,
590 );
591 self.set_property(
592 &ParsedProperty::FontWeight(SpecifiedValue::Specified(weight)),
593 replace,
594 );
595 self.set_property(
596 &ParsedProperty::FontStretch(SpecifiedValue::Specified(stretch)),
597 replace,
598 );
599 self.set_property(
600 &ParsedProperty::FontSize(SpecifiedValue::Specified(size)),
601 replace,
602 );
603 self.set_property(
604 &ParsedProperty::LineHeight(SpecifiedValue::Specified(line_height)),
605 replace,
606 );
607 self.set_property(
608 &ParsedProperty::FontFamily(SpecifiedValue::Specified(family)),
609 replace,
610 );
611 }
612
613 fn expand_marker_shorthand(&mut self, marker: &Marker, replace: bool) {
614 let Marker(v) = marker;
615
616 self.set_property(
617 &ParsedProperty::MarkerStart(SpecifiedValue::Specified(MarkerStart(v.clone()))),
618 replace,
619 );
620 self.set_property(
621 &ParsedProperty::MarkerMid(SpecifiedValue::Specified(MarkerMid(v.clone()))),
622 replace,
623 );
624 self.set_property(
625 &ParsedProperty::MarkerEnd(SpecifiedValue::Specified(MarkerEnd(v.clone()))),
626 replace,
627 );
628 }
629
630 fn expand_font_shorthand_inherit(&mut self, replace: bool) {
631 self.set_property(&ParsedProperty::FontStyle(SpecifiedValue::Inherit), replace);
632 self.set_property(
633 &ParsedProperty::FontVariant(SpecifiedValue::Inherit),
634 replace,
635 );
636 self.set_property(
637 &ParsedProperty::FontWeight(SpecifiedValue::Inherit),
638 replace,
639 );
640 self.set_property(
641 &ParsedProperty::FontStretch(SpecifiedValue::Inherit),
642 replace,
643 );
644 self.set_property(&ParsedProperty::FontSize(SpecifiedValue::Inherit), replace);
645 self.set_property(
646 &ParsedProperty::LineHeight(SpecifiedValue::Inherit),
647 replace,
648 );
649 self.set_property(
650 &ParsedProperty::FontFamily(SpecifiedValue::Inherit),
651 replace,
652 );
653 }
654
655 fn expand_marker_shorthand_inherit(&mut self, replace: bool) {
656 self.set_property(
657 &ParsedProperty::MarkerStart(SpecifiedValue::Inherit),
658 replace,
659 );
660 self.set_property(&ParsedProperty::MarkerMid(SpecifiedValue::Inherit), replace);
661 self.set_property(&ParsedProperty::MarkerEnd(SpecifiedValue::Inherit), replace);
662 }
663
664 pub fn set_parsed_property(&mut self, prop: &ParsedProperty) {
665 self.set_property_expanding_shorthands(prop, true);
666 }
667
668 pub fn set_parsed_property_user_agent(&mut self, prop: &ParsedProperty) {
670 self.set_property_expanding_shorthands(prop, false);
671 }
672
673 pub fn to_computed_values(&self, computed: &mut ComputedValues) {
674 macro_rules! compute {
675 ($name:ident, $field:ident) => {{
676 let prop_val = self.get_property(PropertyId::$name);
681 if let ParsedProperty::$name(s) = prop_val {
682 computed.set_value(ComputedValue::$name(
683 s.compute(&computed.$field(), computed),
684 ));
685 } else {
686 unreachable!();
687 }
688 }};
689 }
690
691 compute!(FontSize, font_size);
697
698 compute!(BaselineShift, baseline_shift);
701 compute!(ClipPath, clip_path);
702 compute!(ClipRule, clip_rule);
703 compute!(Color, color);
704 compute!(ColorInterpolationFilters, color_interpolation_filters);
705 compute!(CX, cx);
706 compute!(CY, cy);
707 compute!(Direction, direction);
708 compute!(Display, display);
709 compute!(DominantBaseline, dominant_baseline);
710 compute!(EnableBackground, enable_background);
711 compute!(Fill, fill);
712 compute!(FillOpacity, fill_opacity);
713 compute!(FillRule, fill_rule);
714 compute!(Filter, filter);
715 compute!(FloodColor, flood_color);
716 compute!(FloodOpacity, flood_opacity);
717 compute!(FontFamily, font_family);
718 compute!(FontStretch, font_stretch);
719 compute!(FontStyle, font_style);
720 compute!(FontVariant, font_variant);
721 compute!(FontWeight, font_weight);
722 compute!(GlyphOrientationVertical, glyph_orientation_vertical);
723 compute!(Height, height);
724 compute!(ImageRendering, image_rendering);
725 compute!(Isolation, isolation);
726 compute!(LetterSpacing, letter_spacing);
727 compute!(LightingColor, lighting_color);
728 compute!(MarkerEnd, marker_end);
729 compute!(MarkerMid, marker_mid);
730 compute!(MarkerStart, marker_start);
731 compute!(Mask, mask);
732 compute!(MaskType, mask_type);
733 compute!(MixBlendMode, mix_blend_mode);
734 compute!(Opacity, opacity);
735 compute!(Overflow, overflow);
736 compute!(PaintOrder, paint_order);
737 compute!(R, r);
738 compute!(RX, rx);
739 compute!(RY, ry);
740 compute!(ShapeRendering, shape_rendering);
741 compute!(StopColor, stop_color);
742 compute!(StopOpacity, stop_opacity);
743 compute!(Stroke, stroke);
744 compute!(StrokeDasharray, stroke_dasharray);
745 compute!(StrokeDashoffset, stroke_dashoffset);
746 compute!(StrokeLinecap, stroke_line_cap);
747 compute!(StrokeLinejoin, stroke_line_join);
748 compute!(StrokeOpacity, stroke_opacity);
749 compute!(StrokeMiterlimit, stroke_miterlimit);
750 compute!(StrokeWidth, stroke_width);
751 compute!(TextAnchor, text_anchor);
752 compute!(TextDecoration, text_decoration);
753 compute!(TextOrientation, text_orientation);
754 compute!(TextRendering, text_rendering);
755 compute!(TransformProperty, transform_property);
756 compute!(UnicodeBidi, unicode_bidi);
757 compute!(VectorEffect, vector_effect);
758 compute!(Visibility, visibility);
759 compute!(Width, width);
760 compute!(WhiteSpace, white_space);
761 compute!(WritingMode, writing_mode);
762 compute!(X, x);
763 compute!(XmlSpace, xml_space);
764 compute!(XmlLang, xml_lang);
765 compute!(Y, y);
766
767 computed.transform = self.transform.unwrap_or_else(|| {
768 match self.get_property(PropertyId::TransformProperty) {
769 ParsedProperty::TransformProperty(SpecifiedValue::Specified(ref t)) => {
770 t.to_transform()
771 }
772 _ => Transform::identity(),
773 }
774 });
775 }
776
777 pub fn inherit_xml_lang(
782 &self,
783 computed: &mut ComputedValues,
784 parent: Option<crate::node::Node>,
785 ) {
786 use crate::node::NodeBorrow;
787 let prop_val = self.get_property(PropertyId::XmlLang);
788 if let ParsedProperty::XmlLang(s) = prop_val {
789 if let Some(parent) = parent {
790 computed.set_value(ComputedValue::XmlLang(
791 parent.borrow_element().get_computed_values().xml_lang(),
792 ));
793 }
794 computed.set_value(ComputedValue::XmlLang(
795 s.compute(&computed.xml_lang(), computed),
796 ));
797 } else {
798 unreachable!();
799 }
800 }
801
802 fn parse_one_presentation_attribute(&mut self, session: &Session, attr: QualName, value: &str) {
803 let mut input = ParserInput::new(value);
804 let mut parser = Parser::new(&mut input);
805
806 match parse_value(&attr, &mut parser, ParseAs::PresentationAttr) {
807 Ok(prop) => {
808 if parser.expect_exhausted().is_ok() {
809 self.set_parsed_property(&prop);
810 } else {
811 rsvg_log!(
812 session,
813 "(ignoring invalid presentation attribute {:?}\n value=\"{}\")\n",
814 attr.expanded(),
815 value,
816 );
817 }
818 }
819
820 Err(ParseError {
822 kind: ParseErrorKind::Custom(ValueErrorKind::UnknownProperty),
823 ..
824 }) => (),
825
826 Err(ParseError {
830 kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)),
831 ..
832 }) => {
833 let mut tok = String::new();
834
835 t.to_css(&mut tok).unwrap(); rsvg_log!(
837 session,
838 "(ignoring invalid presentation attribute {:?}\n value=\"{}\"\n \
839 unexpected token '{}')",
840 attr.expanded(),
841 value,
842 tok,
843 );
844 }
845
846 Err(ParseError {
847 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
848 ..
849 }) => {
850 rsvg_log!(
851 session,
852 "(ignoring invalid presentation attribute {:?}\n value=\"{}\"\n \
853 unexpected end of input)",
854 attr.expanded(),
855 value,
856 );
857 }
858
859 Err(ParseError {
860 kind: ParseErrorKind::Basic(_),
861 ..
862 }) => {
863 rsvg_log!(
864 session,
865 "(ignoring invalid presentation attribute {:?}\n value=\"{}\"\n \
866 unexpected error)",
867 attr.expanded(),
868 value,
869 );
870 }
871
872 Err(ParseError {
873 kind: ParseErrorKind::Custom(ref v),
874 ..
875 }) => {
876 rsvg_log!(
877 session,
878 "(ignoring invalid presentation attribute {:?}\n value=\"{}\"\n {})",
879 attr.expanded(),
880 value,
881 v
882 );
883 }
884 }
885 }
886
887 pub fn parse_presentation_attributes(&mut self, session: &Session, attrs: &Attributes) {
888 for (attr, value) in attrs.iter() {
889 match attr.expanded() {
890 expanded_name!("", "transform") => {
891 let transform_attr = TransformAttribute::parse_str(value)
895 .unwrap_or_else(|_| TransformAttribute::default());
896 self.transform = Some(transform_attr.to_transform());
897 }
898
899 expanded_name!(xml "lang") => {
900 let parse_result: Result<XmlLang, _> = attr.parse(value);
904 match parse_result {
905 Ok(lang) => {
906 self.set_parsed_property(&ParsedProperty::XmlLang(
907 SpecifiedValue::Specified(lang),
908 ));
909 }
910
911 Err(e) => {
912 rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
913 }
914 }
915 }
916
917 expanded_name!(xml "space") => {
918 let parse_result: Result<XmlSpace, _> = attr.parse(value);
922 match parse_result {
923 Ok(space) => {
924 self.set_parsed_property(&ParsedProperty::XmlSpace(
925 SpecifiedValue::Specified(space),
926 ));
927 }
928
929 Err(e) => {
930 rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
931 }
932 }
933 }
934
935 _ => self.parse_one_presentation_attribute(session, attr, value),
936 }
937 }
938 }
939
940 pub fn set_property_from_declaration(
941 &mut self,
942 declaration: &Declaration,
943 origin: Origin,
944 important_styles: &mut HashSet<QualName>,
945 ) {
946 if !declaration.important && important_styles.contains(&declaration.prop_name) {
947 return;
948 }
949
950 if declaration.important {
951 important_styles.insert(declaration.prop_name.clone());
952 }
953
954 if origin == Origin::UserAgent {
955 self.set_parsed_property_user_agent(&declaration.property);
956 } else {
957 self.set_parsed_property(&declaration.property);
958 }
959 }
960
961 pub fn parse_style_declarations(
962 &mut self,
963 declarations: &str,
964 origin: Origin,
965 important_styles: &mut HashSet<QualName>,
966 session: &Session,
967 ) {
968 let mut input = ParserInput::new(declarations);
969 let mut parser = Parser::new(&mut input);
970
971 RuleBodyParser::new(&mut parser, &mut DeclParser)
972 .filter_map(|r| match r {
973 Ok(RuleBodyItem::Decl(decl)) => Some(decl),
974 Ok(RuleBodyItem::Rule(_)) => None,
975 Err(e) => {
976 rsvg_log!(session, "Invalid declaration; ignoring: {:?}", e);
977 None
978 }
979 })
980 .for_each(|decl| self.set_property_from_declaration(&decl, origin, important_styles));
981 }
982}
983
984fn parse_input<'i, T>(input: &mut Parser<'i, '_>) -> Result<SpecifiedValue<T>, ParseError<'i>>
986where
987 T: Property + Clone + Default + Parse,
988{
989 if input
990 .try_parse(|p| p.expect_ident_matching("inherit"))
991 .is_ok()
992 {
993 Ok(SpecifiedValue::Inherit)
994 } else {
995 Parse::parse(input).map(SpecifiedValue::Specified)
996 }
997}
998
999#[cfg(test)]
1000mod tests {
1001 use super::*;
1002 use crate::iri::Iri;
1003 use crate::length::*;
1004
1005 #[test]
1006 fn empty_values_computes_to_defaults() {
1007 let specified = SpecifiedValues::default();
1008
1009 let mut computed = ComputedValues::default();
1010 specified.to_computed_values(&mut computed);
1011
1012 assert_eq!(computed.stroke_width(), StrokeWidth::default());
1013 }
1014
1015 #[test]
1016 fn set_one_property() {
1017 let length = Length::<Both>::new(42.0, LengthUnit::Px);
1018
1019 let mut specified = SpecifiedValues::default();
1020 specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1021 StrokeWidth(length),
1022 )));
1023
1024 let mut computed = ComputedValues::default();
1025 specified.to_computed_values(&mut computed);
1026
1027 assert_eq!(computed.stroke_width(), StrokeWidth(length));
1028 }
1029
1030 #[test]
1031 fn replace_existing_property() {
1032 let length1 = Length::<Both>::new(42.0, LengthUnit::Px);
1033 let length2 = Length::<Both>::new(42.0, LengthUnit::Px);
1034
1035 let mut specified = SpecifiedValues::default();
1036
1037 specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1038 StrokeWidth(length1),
1039 )));
1040
1041 specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1042 StrokeWidth(length2),
1043 )));
1044
1045 let mut computed = ComputedValues::default();
1046 specified.to_computed_values(&mut computed);
1047
1048 assert_eq!(computed.stroke_width(), StrokeWidth(length2));
1049 }
1050
1051 #[test]
1052 fn expands_marker_shorthand() {
1053 let mut specified = SpecifiedValues::default();
1054 let iri = Iri::parse_str("url(#foo)").unwrap();
1055
1056 let marker = Marker(iri.clone());
1057 specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker)));
1058
1059 let mut computed = ComputedValues::default();
1060 specified.to_computed_values(&mut computed);
1061
1062 assert_eq!(computed.marker_start(), MarkerStart(iri.clone()));
1063 assert_eq!(computed.marker_mid(), MarkerMid(iri.clone()));
1064 assert_eq!(computed.marker_end(), MarkerEnd(iri.clone()));
1065 }
1066
1067 #[test]
1068 fn replaces_marker_shorthand() {
1069 let mut specified = SpecifiedValues::default();
1070 let iri1 = Iri::parse_str("url(#foo)").unwrap();
1071 let iri2 = Iri::None;
1072
1073 let marker1 = Marker(iri1.clone());
1074 specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker1)));
1075
1076 let marker2 = Marker(iri2.clone());
1077 specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker2)));
1078
1079 let mut computed = ComputedValues::default();
1080 specified.to_computed_values(&mut computed);
1081
1082 assert_eq!(computed.marker_start(), MarkerStart(iri2.clone()));
1083 assert_eq!(computed.marker_mid(), MarkerMid(iri2.clone()));
1084 assert_eq!(computed.marker_end(), MarkerEnd(iri2.clone()));
1085 }
1086
1087 #[test]
1088 fn computes_property_that_does_not_inherit_automatically() {
1089 assert!(!<Opacity as Property>::inherits_automatically());
1090
1091 let half_opacity = Opacity::parse_str("0.5").unwrap();
1092
1093 let mut with_opacity = SpecifiedValues::default();
1096 with_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Specified(
1097 half_opacity.clone(),
1098 )));
1099
1100 let mut computed_0_5 = ComputedValues::default();
1101 with_opacity.to_computed_values(&mut computed_0_5);
1102
1103 assert_eq!(computed_0_5.opacity(), half_opacity.clone());
1104
1105 let without_opacity = SpecifiedValues::default();
1108
1109 let mut computed = computed_0_5.clone();
1110 without_opacity.to_computed_values(&mut computed);
1111
1112 assert_eq!(computed.opacity(), Opacity::default());
1113
1114 let mut with_inherit_opacity = SpecifiedValues::default();
1117 with_inherit_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Inherit));
1118
1119 let mut computed = computed_0_5.clone();
1120 with_inherit_opacity.to_computed_values(&mut computed);
1121
1122 assert_eq!(computed.opacity(), half_opacity.clone());
1123 }
1124}