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 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 fn parse_one_presentation_attribute(&mut self, session: &Session, attr: QualName, value: &str) {
816 let mut input = ParserInput::new(value);
817 let mut parser = Parser::new(&mut input);
818
819 match parse_value(&attr, &mut parser, ParseAs::PresentationAttr) {
820 Ok(prop) => {
821 if parser.expect_exhausted().is_ok() {
822 self.set_parsed_property(&prop);
823 } else {
824 rsvg_log!(
825 session,
826 "(ignoring invalid presentation attribute {:?}\n value=\"{}\")\n",
827 attr.expanded(),
828 value,
829 );
830 }
831 }
832
833 Err(ParseError {
835 kind: ParseErrorKind::Custom(ValueErrorKind::UnknownProperty),
836 ..
837 }) => (),
838
839 Err(ParseError {
843 kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)),
844 ..
845 }) => {
846 let mut tok = String::new();
847
848 t.to_css(&mut tok).unwrap(); rsvg_log!(
850 session,
851 "(ignoring invalid presentation attribute {:?}\n value=\"{}\"\n \
852 unexpected token '{}')",
853 attr.expanded(),
854 value,
855 tok,
856 );
857 }
858
859 Err(ParseError {
860 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
861 ..
862 }) => {
863 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 kind: ParseErrorKind::Custom(ref v),
887 ..
888 }) => {
889 rsvg_log!(
890 session,
891 "(ignoring invalid presentation attribute {:?}\n value=\"{}\"\n {})",
892 attr.expanded(),
893 value,
894 v
895 );
896 }
897 }
898 }
899
900 pub fn parse_presentation_attributes(&mut self, session: &Session, attrs: &Attributes) {
901 for (attr, value) in attrs.iter() {
902 match attr.expanded() {
903 expanded_name!("", "transform") => {
904 let transform_attr = TransformAttribute::parse_str(value)
908 .unwrap_or_else(|_| TransformAttribute::default());
909 self.transform = Some(transform_attr.to_transform());
910 }
911
912 expanded_name!(xml "lang") => {
913 let parse_result: Result<XmlLang, _> = attr.parse(value);
917 match parse_result {
918 Ok(lang) => {
919 self.set_parsed_property(&ParsedProperty::XmlLang(
920 SpecifiedValue::Specified(lang),
921 ));
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 let parse_result: Result<XmlSpace, _> = attr.parse(value);
935 match parse_result {
936 Ok(space) => {
937 self.set_parsed_property(&ParsedProperty::XmlSpace(
938 SpecifiedValue::Specified(space),
939 ));
940 }
941
942 Err(e) => {
943 rsvg_log!(session, "ignoring attribute with invalid value: {}", e);
944 }
945 }
946 }
947
948 _ => self.parse_one_presentation_attribute(session, attr, value),
949 }
950 }
951 }
952
953 pub fn set_property_from_declaration(
954 &mut self,
955 declaration: &Declaration,
956 origin: Origin,
957 important_styles: &mut HashSet<QualName>,
958 ) {
959 if !declaration.important && important_styles.contains(&declaration.prop_name) {
960 return;
961 }
962
963 if declaration.important {
964 important_styles.insert(declaration.prop_name.clone());
965 }
966
967 if origin == Origin::UserAgent {
968 self.set_parsed_property_user_agent(&declaration.property);
969 } else {
970 self.set_parsed_property(&declaration.property);
971 }
972 }
973
974 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 let mut input = ParserInput::new(declarations);
982 let mut parser = Parser::new(&mut input);
983
984 RuleBodyParser::new(&mut parser, &mut DeclParser)
985 .filter_map(|r| match r {
986 Ok(RuleBodyItem::Decl(decl)) => Some(decl),
987 Ok(RuleBodyItem::Rule(_)) => None,
988 Err(e) => {
989 rsvg_log!(session, "Invalid declaration; ignoring: {:?}", e);
990 None
991 }
992 })
993 .for_each(|decl| self.set_property_from_declaration(&decl, origin, important_styles));
994 }
995}
996
997fn parse_input<'i, T>(input: &mut Parser<'i, '_>) -> Result<SpecifiedValue<T>, ParseError<'i>>
999where
1000 T: Property + Clone + Default + Parse,
1001{
1002 if input
1003 .try_parse(|p| p.expect_ident_matching("inherit"))
1004 .is_ok()
1005 {
1006 Ok(SpecifiedValue::Inherit)
1007 } else {
1008 Parse::parse(input).map(SpecifiedValue::Specified)
1009 }
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014 use super::*;
1015 use crate::iri::Iri;
1016 use crate::length::*;
1017
1018 #[test]
1019 fn empty_values_computes_to_defaults() {
1020 let specified = SpecifiedValues::default();
1021
1022 let mut computed = ComputedValues::default();
1023 specified.to_computed_values(&mut computed);
1024
1025 assert_eq!(computed.stroke_width(), StrokeWidth::default());
1026 }
1027
1028 #[test]
1029 fn set_one_property() {
1030 let length = Length::<Both>::new(42.0, LengthUnit::Px);
1031
1032 let mut specified = SpecifiedValues::default();
1033 specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1034 StrokeWidth(length),
1035 )));
1036
1037 let mut computed = ComputedValues::default();
1038 specified.to_computed_values(&mut computed);
1039
1040 assert_eq!(computed.stroke_width(), StrokeWidth(length));
1041 }
1042
1043 #[test]
1044 fn replace_existing_property() {
1045 let length1 = Length::<Both>::new(42.0, LengthUnit::Px);
1046 let length2 = Length::<Both>::new(42.0, LengthUnit::Px);
1047
1048 let mut specified = SpecifiedValues::default();
1049
1050 specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1051 StrokeWidth(length1),
1052 )));
1053
1054 specified.set_parsed_property(&ParsedProperty::StrokeWidth(SpecifiedValue::Specified(
1055 StrokeWidth(length2),
1056 )));
1057
1058 let mut computed = ComputedValues::default();
1059 specified.to_computed_values(&mut computed);
1060
1061 assert_eq!(computed.stroke_width(), StrokeWidth(length2));
1062 }
1063
1064 #[test]
1065 fn expands_marker_shorthand() {
1066 let mut specified = SpecifiedValues::default();
1067 let iri = Iri::parse_str("url(#foo)").unwrap();
1068
1069 let marker = Marker(iri.clone());
1070 specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker)));
1071
1072 let mut computed = ComputedValues::default();
1073 specified.to_computed_values(&mut computed);
1074
1075 assert_eq!(computed.marker_start(), MarkerStart(iri.clone()));
1076 assert_eq!(computed.marker_mid(), MarkerMid(iri.clone()));
1077 assert_eq!(computed.marker_end(), MarkerEnd(iri.clone()));
1078 }
1079
1080 #[test]
1081 fn replaces_marker_shorthand() {
1082 let mut specified = SpecifiedValues::default();
1083 let iri1 = Iri::parse_str("url(#foo)").unwrap();
1084 let iri2 = Iri::None;
1085
1086 let marker1 = Marker(iri1.clone());
1087 specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker1)));
1088
1089 let marker2 = Marker(iri2.clone());
1090 specified.set_parsed_property(&ParsedProperty::Marker(SpecifiedValue::Specified(marker2)));
1091
1092 let mut computed = ComputedValues::default();
1093 specified.to_computed_values(&mut computed);
1094
1095 assert_eq!(computed.marker_start(), MarkerStart(iri2.clone()));
1096 assert_eq!(computed.marker_mid(), MarkerMid(iri2.clone()));
1097 assert_eq!(computed.marker_end(), MarkerEnd(iri2.clone()));
1098 }
1099
1100 #[test]
1101 fn computes_property_that_does_not_inherit_automatically() {
1102 assert!(!<Opacity as Property>::inherits_automatically());
1103
1104 let half_opacity = Opacity::parse_str("0.5").unwrap();
1105
1106 let mut with_opacity = SpecifiedValues::default();
1109 with_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Specified(
1110 half_opacity.clone(),
1111 )));
1112
1113 let mut computed_0_5 = ComputedValues::default();
1114 with_opacity.to_computed_values(&mut computed_0_5);
1115
1116 assert_eq!(computed_0_5.opacity(), half_opacity.clone());
1117
1118 let without_opacity = SpecifiedValues::default();
1121
1122 let mut computed = computed_0_5.clone();
1123 without_opacity.to_computed_values(&mut computed);
1124
1125 assert_eq!(computed.opacity(), Opacity::default());
1126
1127 let mut with_inherit_opacity = SpecifiedValues::default();
1130 with_inherit_opacity.set_parsed_property(&ParsedProperty::Opacity(SpecifiedValue::Inherit));
1131
1132 let mut computed = computed_0_5.clone();
1133 with_inherit_opacity.to_computed_values(&mut computed);
1134
1135 assert_eq!(computed.opacity(), half_opacity.clone());
1136 }
1137}