lightningcss/properties/
mod.rs

1//! CSS property values.
2//!
3//! Each property provides parsing and serialization support using the [Parse](super::traits::Parse)
4//! and [ToCss](super::traits::ToCss) traits. Properties are fully parsed as defined by the CSS spec,
5//! and printed in their canonical form. For example, most CSS properties are case-insensitive, and
6//! may be written in various orders, but when printed they are lower cased as appropriate and in a
7//! standard order.
8//!
9//! CSS properties often also contain many implicit values that are automatically filled in during
10//! parsing when omitted. These are also omitted when possible during serialization. Many properties
11//! also implement the [Default](std::default::Default) trait, which returns the initial value for the property.
12//!
13//! Shorthand properties are represented as structs containing fields for each of the sub-properties.
14//! If some of the sub-properties are not specified in the shorthand, their default values are filled in.
15//!
16//! The [Property](Property) enum contains the values of all properties, and can be used to parse property values by name.
17//! The [PropertyId](PropertyId) enum represents only property names, and not values and is used to refer to known properties.
18//!
19//! # Example
20//!
21//! This example shows how the `background` shorthand property is parsed and serialized. The `parse_string`
22//! function parses the background into a structure with all missing fields filled in with their default values.
23//! When printed using the `to_css_string` function, the components are in their canonical order, and default
24//! values are removed.
25//!
26//! ```
27//! use smallvec::smallvec;
28//! use lightningcss::{
29//!   properties::{Property, PropertyId, background::*},
30//!   values::{url::Url, image::Image, color::{CssColor, RGBA}, position::*, length::*},
31//!   stylesheet::{ParserOptions, PrinterOptions},
32//!   dependencies::Location,
33//! };
34//!
35//! let background = Property::parse_string(
36//!   PropertyId::from("background"),
37//!   "url('img.png') repeat fixed 20px 10px / 50px 100px",
38//!   ParserOptions::default()
39//! ).unwrap();
40//!
41//! assert_eq!(
42//!   background,
43//!   Property::Background(smallvec![Background {
44//!     image: Image::Url(Url {
45//!       url: "img.png".into(),
46//!       loc: Location { line: 1, column: 1 }
47//!     }),
48//!     color: CssColor::RGBA(RGBA {
49//!       red: 0,
50//!       green: 0,
51//!       blue: 0,
52//!       alpha: 0
53//!     }),
54//!     position: BackgroundPosition {
55//!       x: HorizontalPosition::Length(LengthPercentage::px(20.0)),
56//!       y: VerticalPosition::Length(LengthPercentage::px(10.0)),
57//!     },
58//!     repeat: BackgroundRepeat {
59//!       x: BackgroundRepeatKeyword::Repeat,
60//!       y: BackgroundRepeatKeyword::Repeat,
61//!     },
62//!     size: BackgroundSize::Explicit {
63//!       width: LengthPercentageOrAuto::LengthPercentage(LengthPercentage::px(50.0)),
64//!       height: LengthPercentageOrAuto::LengthPercentage(LengthPercentage::px(100.0)),
65//!     },
66//!     attachment: BackgroundAttachment::Fixed,
67//!     origin: BackgroundOrigin::PaddingBox,
68//!     clip: BackgroundClip::BorderBox,
69//!   }])
70//! );
71//!
72//! assert_eq!(
73//!   background.to_css_string(false, PrinterOptions::default()).unwrap(),
74//!   r#"background: url("img.png") 20px 10px / 50px 100px fixed"#
75//! );
76//! ```
77//!
78//! If you have a [cssparser::Parser](cssparser::Parser) already, you can also use the `parse` and `to_css`
79//! methods instead, rather than parsing from a string.
80//!
81//! # Unparsed and custom properties
82//!
83//! Custom and unknown properties are represented by the [CustomProperty](custom::CustomProperty) struct, and the
84//! `Property::Custom` variant. The value of these properties is not parsed, and is stored as a raw
85//! [TokenList](custom::TokenList), with the name as a string.
86//!
87//! If a known property is unable to be parsed, e.g. it contains `var()` references, then it is represented by the
88//! [UnparsedProperty](custom::UnparsedProperty) struct, and the `Property::Unparsed` variant. The value is stored
89//! as a raw [TokenList](custom::TokenList), with a [PropertyId](PropertyId) as the name.
90
91#![deny(missing_docs)]
92
93pub mod align;
94pub mod animation;
95pub mod background;
96pub mod border;
97pub mod border_image;
98pub mod border_radius;
99pub mod box_shadow;
100pub mod contain;
101pub mod css_modules;
102pub mod custom;
103pub mod display;
104pub mod effects;
105pub mod flex;
106pub mod font;
107#[cfg(feature = "grid")]
108pub mod grid;
109pub mod list;
110pub(crate) mod margin_padding;
111pub mod masking;
112pub mod outline;
113pub mod overflow;
114pub mod position;
115pub(crate) mod prefix_handler;
116pub mod size;
117pub mod svg;
118pub mod text;
119pub mod transform;
120pub mod transition;
121pub mod ui;
122
123use crate::declaration::DeclarationBlock;
124use crate::error::{ParserError, PrinterError};
125use crate::logical::{LogicalGroup, PropertyCategory};
126use crate::macros::enum_property;
127use crate::parser::starts_with_ignore_ascii_case;
128use crate::parser::ParserOptions;
129use crate::prefixes::Feature;
130use crate::printer::{Printer, PrinterOptions};
131use crate::targets::Targets;
132use crate::traits::{Parse, ParseWithOptions, Shorthand, ToCss};
133use crate::values::number::{CSSInteger, CSSNumber};
134use crate::values::string::CowArcStr;
135use crate::values::{
136  alpha::*, color::*, easing::EasingFunction, ident::DashedIdentReference, ident::NoneOrCustomIdentList, image::*,
137  length::*, position::*, rect::*, shape::FillRule, size::Size2D, time::Time,
138};
139use crate::vendor_prefix::VendorPrefix;
140#[cfg(feature = "visitor")]
141use crate::visitor::Visit;
142use align::*;
143use animation::*;
144use background::*;
145use border::*;
146use border_image::*;
147use border_radius::*;
148use box_shadow::*;
149use contain::*;
150use css_modules::*;
151use cssparser::*;
152use custom::*;
153use display::*;
154use effects::*;
155use flex::*;
156use font::*;
157#[cfg(feature = "grid")]
158use grid::*;
159use list::*;
160use margin_padding::*;
161use masking::*;
162use outline::*;
163use overflow::*;
164use size::*;
165use smallvec::{smallvec, SmallVec};
166#[cfg(feature = "into_owned")]
167use static_self::IntoOwned;
168use svg::*;
169use text::*;
170use transform::*;
171use transition::*;
172use ui::*;
173
174macro_rules! define_properties {
175  (
176    $(
177      $(#[$meta: meta])*
178      $name: literal: $property: ident($type: ty $(, $vp: ty)?) $( / $prefix: ident )* $( unprefixed: $unprefixed: literal )? $( options: $options: literal )? $( shorthand: $shorthand: literal )? $( [ logical_group: $logical_group: ident, category: $logical_category: ident ] )? $( if $condition: ident )?,
179    )+
180  ) => {
181    /// A CSS property id.
182    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
183    #[cfg_attr(feature = "visitor", derive(Visit))]
184    #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
185    pub enum PropertyId<'i> {
186      $(
187        #[doc=concat!("The `", $name, "` property.")]
188        $(#[$meta])*
189        $property$(($vp))?,
190      )+
191      /// The `all` property.
192      All,
193      /// An unknown or custom property name.
194      Custom(CustomPropertyName<'i>)
195    }
196
197    macro_rules! vp_name {
198      ($x: ty, $n: ident) => {
199        $n
200      };
201      ($x: ty, $n: expr) => {
202        $n
203      };
204    }
205
206    macro_rules! get_allowed_prefixes {
207      ($v: literal) => {
208        VendorPrefix::empty()
209      };
210      () => {
211        VendorPrefix::None
212      };
213    }
214
215    impl<'i> From<CowArcStr<'i>> for PropertyId<'i> {
216      fn from(name: CowArcStr<'i>) -> PropertyId<'i> {
217        let name_ref = name.as_ref();
218        let (prefix, name_ref) = if starts_with_ignore_ascii_case(name_ref, "-webkit-") {
219          (VendorPrefix::WebKit, &name_ref[8..])
220        } else if starts_with_ignore_ascii_case(name_ref, "-moz-") {
221          (VendorPrefix::Moz, &name_ref[5..])
222        } else if starts_with_ignore_ascii_case(name_ref, "-o-") {
223          (VendorPrefix::O, &name_ref[3..])
224        } else if starts_with_ignore_ascii_case(name_ref, "-ms-") {
225          (VendorPrefix::Ms, &name_ref[4..])
226        } else {
227          (VendorPrefix::None, name_ref)
228        };
229
230        Self::from_name_and_prefix(name_ref, prefix)
231          .unwrap_or_else(|_| PropertyId::Custom(name.into()))
232      }
233    }
234
235    impl<'i> From<&'i str> for PropertyId<'i> {
236      #[inline]
237      fn from(name: &'i str) -> PropertyId<'i> {
238        PropertyId::from(CowArcStr::from(name))
239      }
240    }
241
242    impl<'i> Parse<'i> for PropertyId<'i> {
243      fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
244        let name = input.expect_ident()?;
245        Ok(CowArcStr::from(name).into())
246      }
247    }
248
249    impl<'i> ToCss for PropertyId<'i> {
250      fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError> where W: std::fmt::Write {
251        let mut first = true;
252        macro_rules! delim {
253          () => {
254            #[allow(unused_assignments)]
255            if first {
256              first = false;
257            } else {
258              dest.delim(',', false)?;
259            }
260          };
261        }
262
263        let name = self.name();
264        for p in self.prefix().or_none() {
265          delim!();
266          p.to_css(dest)?;
267          dest.write_str(name)?;
268        }
269
270        Ok(())
271      }
272    }
273
274    impl<'i> PropertyId<'i> {
275      fn from_name_and_prefix(name: &str, prefix: VendorPrefix) -> Result<Self, ()> {
276        match_ignore_ascii_case! { name.as_ref(),
277          $(
278            $(#[$meta])*
279            $name => {
280              macro_rules! get_propertyid {
281                ($v: ty) => {
282                  PropertyId::$property(prefix)
283                };
284                () => {
285                  PropertyId::$property
286                };
287              }
288
289              let allowed_prefixes = get_allowed_prefixes!($($unprefixed)?) $(| VendorPrefix::$prefix)*;
290              if allowed_prefixes.contains(prefix) {
291                return Ok(get_propertyid!($($vp)?))
292              }
293            },
294          )+
295          "all" => return Ok(PropertyId::All),
296          _ => {}
297        }
298
299        Err(())
300      }
301
302      /// Returns the vendor prefix for this property id.
303      pub fn prefix(&self) -> VendorPrefix {
304        use PropertyId::*;
305        match self {
306          $(
307            $(#[$meta])*
308            $property$((vp_name!($vp, prefix)))? => {
309              $(
310                macro_rules! return_prefix {
311                  ($v: ty) => {
312                    return *prefix;
313                  };
314                }
315
316                return_prefix!($vp);
317              )?
318              #[allow(unreachable_code)]
319              VendorPrefix::empty()
320            },
321          )+
322          _ => VendorPrefix::empty()
323        }
324      }
325
326      pub(crate) fn with_prefix(&self, prefix: VendorPrefix) -> PropertyId<'i> {
327        use PropertyId::*;
328        match self {
329          $(
330            $(#[$meta])*
331            $property$((vp_name!($vp, _p)))? => {
332              macro_rules! get_prefixed {
333                ($v: ty) => {
334                  PropertyId::$property(prefix)
335                };
336                () => {
337                  PropertyId::$property
338                }
339              }
340
341              get_prefixed!($($vp)?)
342            },
343          )+
344          _ => self.clone()
345        }
346      }
347
348      pub(crate) fn add_prefix(&mut self, prefix: VendorPrefix) {
349        use PropertyId::*;
350        match self {
351          $(
352            $(#[$meta])*
353            $property$((vp_name!($vp, p)))? => {
354              macro_rules! get_prefixed {
355                ($v: ty) => {{
356                  *p |= prefix;
357                }};
358                () => {{}};
359              }
360
361              get_prefixed!($($vp)?)
362            },
363          )+
364          _ => {}
365        }
366      }
367
368      pub(crate) fn set_prefixes_for_targets(&mut self, targets: Targets) {
369        match self {
370          $(
371            $(#[$meta])*
372            #[allow(unused_variables)]
373            PropertyId::$property$((vp_name!($vp, prefix)))? => {
374              macro_rules! get_prefixed {
375                ($v: ty, $u: literal) => {};
376                ($v: ty) => {{
377                  *prefix = targets.prefixes(*prefix, Feature::$property);
378                }};
379                () => {};
380              }
381
382              get_prefixed!($($vp)? $(, $unprefixed)?);
383            },
384          )+
385          _ => {}
386        }
387      }
388
389      /// Returns the property name, without any vendor prefixes.
390      pub fn name(&self) -> &str {
391        use PropertyId::*;
392
393        match self {
394          $(
395            $(#[$meta])*
396            $property$((vp_name!($vp, _p)))? => $name,
397          )+
398          All => "all",
399          Custom(name) => name.as_ref()
400        }
401      }
402
403      /// Returns whether a property is a shorthand.
404      pub fn is_shorthand(&self) -> bool {
405        $(
406          macro_rules! shorthand {
407            ($s: literal) => {
408              if let PropertyId::$property$((vp_name!($vp, _prefix)))? = self {
409                return true
410              }
411            };
412            () => {}
413          }
414
415          shorthand!($($shorthand)?);
416        )+
417
418        false
419      }
420
421      /// Returns a shorthand value for this property id from the given declaration block.
422      pub(crate) fn shorthand_value<'a>(&self, decls: &DeclarationBlock<'a>) -> Option<(Property<'a>, bool)> {
423        // Inline function to remap lifetime names.
424        #[inline]
425        fn shorthand_value<'a, 'i>(property_id: &PropertyId<'a>, decls: &DeclarationBlock<'i>) -> Option<(Property<'i>, bool)> {
426          $(
427            #[allow(unused_macros)]
428            macro_rules! prefix {
429              ($v: ty, $p: ident) => {
430                *$p
431              };
432              ($p: ident) => {
433                VendorPrefix::None
434              };
435            }
436
437            macro_rules! shorthand {
438              ($s: literal) => {
439                if let PropertyId::$property$((vp_name!($vp, prefix)))? = &property_id {
440                  if let Some((val, important)) = <$type>::from_longhands(decls, prefix!($($vp,)? prefix)) {
441                    return Some((Property::$property(val $(, *vp_name!($vp, prefix))?), important))
442                  }
443                }
444              };
445              () => {}
446            }
447
448            shorthand!($($shorthand)?);
449          )+
450
451          None
452        }
453
454        shorthand_value(self, decls)
455      }
456
457      /// Returns a list of longhand property ids for a shorthand.
458      pub fn longhands(&self) -> Option<Vec<PropertyId<'static>>> {
459        macro_rules! prefix_default {
460          ($x: ty, $p: ident) => {
461            *$p
462          };
463          () => {
464            VendorPrefix::None
465          };
466        }
467
468        $(
469          macro_rules! shorthand {
470            ($s: literal) => {
471              if let PropertyId::$property$((vp_name!($vp, prefix)))? = self {
472                return Some(<$type>::longhands(prefix_default!($($vp, prefix)?)));
473              }
474            };
475            () => {}
476          }
477
478          shorthand!($($shorthand)?);
479        )+
480
481        None
482      }
483
484      /// Returns the logical property group for this property.
485      pub(crate) fn logical_group(&self) -> Option<LogicalGroup> {
486        $(
487          macro_rules! group {
488            ($g: ident) => {
489              if let PropertyId::$property$((vp_name!($vp, _prefix)))? = self {
490                return Some(LogicalGroup::$g)
491              }
492            };
493            () => {}
494          }
495
496          group!($($logical_group)?);
497        )+
498
499        None
500      }
501
502      /// Returns whether the property is logical or physical.
503      pub(crate) fn category(&self) -> Option<PropertyCategory> {
504        $(
505          macro_rules! category {
506            ($c: ident) => {
507              if let PropertyId::$property$((vp_name!($vp, _prefix)))? = self {
508                return Some(PropertyCategory::$c)
509              }
510            };
511            () => {}
512          }
513
514          category!($($logical_category)?);
515        )+
516
517        None
518      }
519    }
520
521    #[cfg(feature = "serde")]
522    #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
523    impl<'i> serde::Serialize for PropertyId<'i> {
524      fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
525      where
526        S: serde::Serializer,
527      {
528        use serde::ser::SerializeStruct;
529
530        let name = self.name();
531        let prefix = self.prefix();
532
533        if prefix.is_empty() {
534          let mut s = serializer.serialize_struct("PropertyId", 1)?;
535          s.serialize_field("property", name)?;
536          s.end()
537        } else {
538          let mut s = serializer.serialize_struct("PropertyId", 2)?;
539          s.serialize_field("property", name)?;
540          s.serialize_field("vendor_prefix", &prefix)?;
541          s.end()
542        }
543      }
544    }
545
546    #[cfg(feature = "serde")]
547    #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
548    impl<'i, 'de: 'i> serde::Deserialize<'de> for PropertyId<'i> {
549      fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
550      where
551        D: serde::Deserializer<'de>,
552      {
553        #[derive(serde::Deserialize)]
554        #[serde(field_identifier, rename_all = "snake_case")]
555        enum Field {
556          Property,
557          VendorPrefix
558        }
559
560        struct PropertyIdVisitor;
561        impl<'de> serde::de::Visitor<'de> for PropertyIdVisitor {
562          type Value = PropertyId<'de>;
563
564          fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
565            formatter.write_str("a PropertyId")
566          }
567
568          fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
569          where
570            A: serde::de::MapAccess<'de>,
571          {
572            let mut property: Option<CowArcStr> = None;
573            let mut vendor_prefix = None;
574            while let Some(key) = map.next_key()? {
575              match key {
576                Field::Property => {
577                  property = Some(map.next_value()?);
578                }
579                Field::VendorPrefix => {
580                  vendor_prefix = Some(map.next_value()?);
581                }
582              }
583            }
584
585            let property = property.ok_or_else(|| serde::de::Error::missing_field("property"))?;
586            let vendor_prefix = vendor_prefix.unwrap_or(VendorPrefix::None);
587            let property_id = PropertyId::from_name_and_prefix(property.as_ref(), vendor_prefix)
588              .unwrap_or_else(|_| PropertyId::Custom(property.into()));
589            Ok(property_id)
590          }
591        }
592
593        deserializer.deserialize_any(PropertyIdVisitor)
594      }
595    }
596
597    #[cfg(feature = "jsonschema")]
598    #[cfg_attr(docsrs, doc(cfg(feature = "jsonschema")))]
599    impl<'i> schemars::JsonSchema for PropertyId<'i> {
600      fn is_referenceable() -> bool {
601        true
602      }
603
604      fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
605        macro_rules! property {
606          ($n: literal) => {
607            fn property(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
608              schemars::schema::Schema::Object(schemars::schema::SchemaObject {
609                instance_type: Some(schemars::schema::InstanceType::String.into()),
610                enum_values: Some(vec![$n.into()]),
611                ..Default::default()
612              })
613            }
614          }
615        }
616
617        schemars::schema::Schema::Object(schemars::schema::SchemaObject {
618          subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
619            one_of: Some(vec![
620              $(
621                {
622                  property!($name);
623
624                  macro_rules! with_prefix {
625                    ($v: ty) => {{
626                      #[derive(schemars::JsonSchema)]
627                      struct T<'i> {
628                        #[schemars(rename = "property", schema_with = "property")]
629                        _property: &'i u8,
630                        #[schemars(rename = "vendorPrefix")]
631                        _vendor_prefix: VendorPrefix,
632                      }
633
634                      T::json_schema(gen)
635                    }};
636                    () => {{
637                      #[derive(schemars::JsonSchema)]
638                      struct T<'i> {
639                        #[schemars(rename = "property", schema_with = "property")]
640                        _property: &'i u8,
641                      }
642
643                      T::json_schema(gen)
644                    }};
645                  }
646
647                  with_prefix!($($vp)?)
648                },
649              )+
650              {
651                property!("all");
652
653                #[derive(schemars::JsonSchema)]
654                struct T<'i> {
655                  #[schemars(rename = "property", schema_with = "property")]
656                  _property: &'i u8,
657                }
658
659                T::json_schema(gen)
660              },
661              {
662                #[derive(schemars::JsonSchema)]
663                struct T {
664                  #[schemars(rename = "property")]
665                  _property: String,
666                }
667
668                T::json_schema(gen)
669              }
670            ]),
671            ..Default::default()
672          })),
673          ..Default::default()
674        })
675      }
676
677      fn schema_name() -> String {
678        "PropertyId".into()
679      }
680    }
681
682    /// A CSS property.
683    #[derive(Debug, Clone, PartialEq)]
684    #[cfg_attr(feature = "visitor", derive(Visit), visit(visit_property, PROPERTIES))]
685    #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
686    pub enum Property<'i> {
687      $(
688        #[doc=concat!("The `", $name, "` property.")]
689        $(#[$meta])*
690        $property($type, $($vp)?),
691      )+
692      /// The [all](https://drafts.csswg.org/css-cascade-5/#all-shorthand) shorthand property.
693      All(CSSWideKeyword),
694      /// An unparsed property.
695      Unparsed(UnparsedProperty<'i>),
696      /// A custom or unknown property.
697      Custom(CustomProperty<'i>),
698    }
699
700    impl<'i> Property<'i> {
701      /// Parses a CSS property by name.
702      pub fn parse<'t>(property_id: PropertyId<'i>, input: &mut Parser<'i, 't>, options: &ParserOptions<'_, 'i>) -> Result<Property<'i>, ParseError<'i, ParserError<'i>>> {
703        let state = input.state();
704
705        match property_id {
706          $(
707            $(#[$meta])*
708            PropertyId::$property$((vp_name!($vp, prefix)))? $(if options.$condition.is_some())? => {
709              if let Ok(c) = <$type>::parse_with_options(input, options) {
710                if input.expect_exhausted().is_ok() {
711                  return Ok(Property::$property(c $(, vp_name!($vp, prefix))?))
712                }
713              }
714            },
715          )+
716          PropertyId::All => return Ok(Property::All(CSSWideKeyword::parse(input)?)),
717          PropertyId::Custom(name) => return Ok(Property::Custom(CustomProperty::parse(name, input, options)?)),
718          _ => {}
719        };
720
721        // If a value was unable to be parsed, treat as an unparsed property.
722        // This is different from a custom property, handled below, in that the property name is known
723        // and stored as an enum rather than a string. This lets property handlers more easily deal with it.
724        // Ideally we'd only do this if var() or env() references were seen, but err on the safe side for now.
725        input.reset(&state);
726        return Ok(Property::Unparsed(UnparsedProperty::parse(property_id, input, options)?))
727      }
728
729      /// Returns the property id for this property.
730      pub fn property_id(&self) -> PropertyId<'i> {
731        use Property::*;
732
733        match self {
734          $(
735            $(#[$meta])*
736            $property(_, $(vp_name!($vp, p))?) => PropertyId::$property$((*vp_name!($vp, p)))?,
737          )+
738          All(_) => PropertyId::All,
739          Unparsed(unparsed) => unparsed.property_id.clone(),
740          Custom(custom) => PropertyId::Custom(custom.name.clone())
741        }
742      }
743
744      /// Parses a CSS property from a string.
745      pub fn parse_string(property_id: PropertyId<'i>, input: &'i str, options: ParserOptions<'_, 'i>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
746        let mut input = ParserInput::new(input);
747        let mut parser = Parser::new(&mut input);
748        Self::parse(property_id, &mut parser, &options)
749      }
750
751      /// Sets the vendor prefixes for this property.
752      ///
753      /// If the property doesn't support vendor prefixes, this function does nothing.
754      /// If vendor prefixes are set which do not exist for the property, they are ignored
755      /// and only the valid prefixes are set.
756      pub fn set_prefix(&mut self, prefix: VendorPrefix) {
757        use Property::*;
758        match self {
759          $(
760            $(#[$meta])*
761            $property(_, $(vp_name!($vp, p))?) => {
762              macro_rules! set {
763                ($v: ty) => {
764                  *p = (prefix & (get_allowed_prefixes!($($unprefixed)?) $(| VendorPrefix::$prefix)*)).or(*p);
765                };
766                () => {};
767              }
768
769              set!($($vp)?);
770            },
771          )+
772          _ => {}
773        }
774      }
775
776      /// Serializes the value of a CSS property without its name or `!important` flag.
777      pub fn value_to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError> where W: std::fmt::Write {
778        use Property::*;
779
780        match self {
781          $(
782            $(#[$meta])*
783            $property(val, $(vp_name!($vp, _p))?) => {
784              val.to_css(dest)
785            }
786          )+
787          All(keyword) => keyword.to_css(dest),
788          Unparsed(unparsed) => {
789            unparsed.value.to_css(dest, false)
790          }
791          Custom(custom) => {
792            custom.value.to_css(dest, matches!(custom.name, CustomPropertyName::Custom(..)))
793          }
794        }
795      }
796
797      /// Serializes the value of a CSS property as a string.
798      pub fn value_to_css_string(&self, options: PrinterOptions) -> Result<String, PrinterError> {
799        let mut s = String::new();
800        let mut printer = Printer::new(&mut s, options);
801        self.value_to_css(&mut printer)?;
802        Ok(s)
803      }
804
805      /// Serializes the CSS property, with an optional `!important` flag.
806      pub fn to_css<W>(&self, dest: &mut Printer<W>, important: bool) -> Result<(), PrinterError> where W: std::fmt::Write {
807        use Property::*;
808
809        let mut first = true;
810        macro_rules! start {
811          () => {
812            #[allow(unused_assignments)]
813            if first {
814              first = false;
815            } else {
816              dest.write_char(';')?;
817              dest.newline()?;
818            }
819          };
820        }
821
822        macro_rules! write_important {
823          () => {
824            if important {
825              dest.whitespace()?;
826              dest.write_str("!important")?;
827            }
828          }
829        }
830
831        let (name, prefix) = match self {
832          $(
833            $(#[$meta])*
834            $property(_, $(vp_name!($vp, prefix))?) => {
835              macro_rules! get_prefix {
836                ($v: ty) => {
837                  *prefix
838                };
839                () => {
840                  VendorPrefix::None
841                };
842              }
843
844              ($name, get_prefix!($($vp)?))
845            },
846          )+
847          All(_) => ("all", VendorPrefix::None),
848          Unparsed(unparsed) => {
849            let mut prefix = unparsed.property_id.prefix();
850            if prefix.is_empty() {
851              prefix = VendorPrefix::None;
852            }
853            (unparsed.property_id.name(), prefix)
854          },
855          Custom(custom) => {
856            custom.name.to_css(dest)?;
857            dest.delim(':', false)?;
858            self.value_to_css(dest)?;
859            write_important!();
860            return Ok(())
861          }
862        };
863        for p in prefix {
864          start!();
865          p.to_css(dest)?;
866          dest.write_str(name)?;
867          dest.delim(':', false)?;
868          self.value_to_css(dest)?;
869          write_important!();
870        }
871        Ok(())
872      }
873
874      /// Serializes the CSS property to a string, with an optional `!important` flag.
875      pub fn to_css_string(&self, important: bool, options: PrinterOptions) -> Result<String, PrinterError> {
876        let mut s = String::new();
877        let mut printer = Printer::new(&mut s, options);
878        self.to_css(&mut printer, important)?;
879        Ok(s)
880      }
881
882      /// Returns the given longhand property for a shorthand.
883      pub fn longhand(&self, property_id: &PropertyId) -> Option<Property<'i>> {
884        $(
885          macro_rules! shorthand {
886            ($s: literal) => {
887              if let Property::$property(val $(, vp_name!($vp, prefix))?) = self {
888                $(
889                  if *vp_name!($vp, prefix) != property_id.prefix() {
890                    return None
891                  }
892                )?
893                return val.longhand(property_id)
894              }
895            };
896            () => {}
897          }
898
899          shorthand!($($shorthand)?);
900        )+
901
902        None
903      }
904
905      /// Updates this shorthand from a longhand property.
906      pub fn set_longhand(&mut self, property: &Property<'i>) -> Result<(), ()> {
907        $(
908          macro_rules! shorthand {
909            ($s: literal) => {
910              if let Property::$property(val $(, vp_name!($vp, prefix))?) = self {
911                $(
912                  if *vp_name!($vp, prefix) != property.property_id().prefix() {
913                    return Err(())
914                  }
915                )?
916                return val.set_longhand(property)
917              }
918            };
919            () => {}
920          }
921
922          shorthand!($($shorthand)?);
923        )+
924        Err(())
925      }
926    }
927
928    #[cfg(feature = "serde")]
929    #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
930    impl<'i> serde::Serialize for Property<'i> {
931      fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
932      where
933        S: serde::Serializer,
934      {
935        use serde::ser::SerializeStruct;
936        use Property::*;
937
938        match self {
939          Unparsed(unparsed) => {
940            let mut s = serializer.serialize_struct("Property", 2)?;
941            s.serialize_field("property", "unparsed")?;
942            s.serialize_field("value", unparsed)?;
943            return s.end()
944          }
945          Custom(unparsed) => {
946            let mut s = serializer.serialize_struct("Property", 2)?;
947            s.serialize_field("property", "custom")?;
948            s.serialize_field("value", unparsed)?;
949            return s.end()
950          }
951          _ => {}
952        }
953
954        let id = self.property_id();
955        let name = id.name();
956        let prefix = id.prefix();
957
958        let mut s = if prefix.is_empty() {
959          let mut s = serializer.serialize_struct("Property", 2)?;
960          s.serialize_field("property", name)?;
961          s
962        } else {
963          let mut s = serializer.serialize_struct("Property", 3)?;
964          s.serialize_field("property", name)?;
965          s.serialize_field("vendorPrefix", &prefix)?;
966          s
967        };
968
969        match self {
970          $(
971            $(#[$meta])*
972            $property(value, $(vp_name!($vp, _p))?) => {
973              s.serialize_field("value", value)?;
974            }
975          )+
976          All(value) => {
977            s.serialize_field("value", value)?;
978          }
979          Unparsed(_) | Custom(_) => unreachable!()
980        }
981
982        s.end()
983      }
984    }
985
986    #[cfg(feature = "serde")]
987    #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
988    impl<'i, 'de: 'i> serde::Deserialize<'de> for Property<'i> {
989      fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
990      where
991        D: serde::Deserializer<'de>,
992      {
993        enum ContentOrRaw<'de> {
994          Content(serde::__private::de::Content<'de>),
995          Raw(CowArcStr<'de>)
996        }
997
998        struct PartialProperty<'de> {
999          property_id: PropertyId<'de>,
1000          value: ContentOrRaw<'de>,
1001        }
1002
1003        #[derive(serde::Deserialize)]
1004        #[serde(field_identifier, rename_all = "camelCase")]
1005        enum Field {
1006          Property,
1007          VendorPrefix,
1008          Value,
1009          Raw
1010        }
1011
1012        struct PropertyIdVisitor;
1013        impl<'de> serde::de::Visitor<'de> for PropertyIdVisitor {
1014          type Value = PartialProperty<'de>;
1015
1016          fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1017            formatter.write_str("a Property")
1018          }
1019
1020          fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
1021          where
1022            A: serde::de::MapAccess<'de>,
1023          {
1024            let mut property: Option<CowArcStr> = None;
1025            let mut vendor_prefix = None;
1026            let mut value: Option<ContentOrRaw<'de>> = None;
1027            while let Some(key) = map.next_key()? {
1028              match key {
1029                Field::Property => {
1030                  property = Some(map.next_value()?);
1031                }
1032                Field::VendorPrefix => {
1033                  vendor_prefix = Some(map.next_value()?);
1034                }
1035                Field::Value => {
1036                  value = Some(ContentOrRaw::Content(map.next_value()?));
1037                }
1038                Field::Raw => {
1039                  value = Some(ContentOrRaw::Raw(map.next_value()?));
1040                }
1041              }
1042            }
1043
1044            let property = property.ok_or_else(|| serde::de::Error::missing_field("property"))?;
1045            let vendor_prefix = vendor_prefix.unwrap_or(VendorPrefix::None);
1046            let value = value.ok_or_else(|| serde::de::Error::missing_field("value"))?;
1047            let property_id = PropertyId::from_name_and_prefix(property.as_ref(), vendor_prefix)
1048              .unwrap_or_else(|_| PropertyId::from(property));
1049            Ok(PartialProperty {
1050              property_id,
1051              value,
1052            })
1053          }
1054        }
1055
1056        let partial = deserializer.deserialize_any(PropertyIdVisitor)?;
1057
1058        let content = match partial.value {
1059          ContentOrRaw::Raw(raw) => {
1060            let res = Property::parse_string(partial.property_id, raw.as_ref(), ParserOptions::default())
1061              .map_err(|_| serde::de::Error::custom("Could not parse value"))?;
1062            return Ok(res.into_owned())
1063          }
1064          ContentOrRaw::Content(content) => content
1065        };
1066
1067        let deserializer = serde::__private::de::ContentDeserializer::new(content);
1068        match partial.property_id {
1069          $(
1070            $(#[$meta])*
1071            PropertyId::$property$((vp_name!($vp, prefix)))? => {
1072              let value = <$type>::deserialize(deserializer)?;
1073              Ok(Property::$property(value $(, vp_name!($vp, prefix))?))
1074            },
1075          )+
1076          PropertyId::Custom(name) => {
1077            if name.as_ref() == "unparsed" {
1078              let value = UnparsedProperty::deserialize(deserializer)?;
1079              Ok(Property::Unparsed(value))
1080            } else {
1081              let value = CustomProperty::deserialize(deserializer)?;
1082              Ok(Property::Custom(value))
1083            }
1084          }
1085          PropertyId::All => {
1086            let value = CSSWideKeyword::deserialize(deserializer)?;
1087            Ok(Property::All(value))
1088          }
1089        }
1090      }
1091    }
1092
1093    #[cfg(feature = "jsonschema")]
1094    #[cfg_attr(docsrs, doc(cfg(feature = "jsonschema")))]
1095    impl<'i> schemars::JsonSchema for Property<'i> {
1096      fn is_referenceable() -> bool {
1097        true
1098      }
1099
1100      fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1101        macro_rules! property {
1102          ($n: literal) => {
1103            fn property(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1104              schemars::schema::Schema::Object(schemars::schema::SchemaObject {
1105                instance_type: Some(schemars::schema::InstanceType::String.into()),
1106                enum_values: Some(vec![$n.into()]),
1107                ..Default::default()
1108              })
1109            }
1110          }
1111        }
1112
1113        schemars::schema::Schema::Object(schemars::schema::SchemaObject {
1114          subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
1115            one_of: Some(vec![
1116              $(
1117                {
1118                  property!($name);
1119
1120                  macro_rules! with_prefix {
1121                    ($v: ty) => {{
1122                      #[derive(schemars::JsonSchema)]
1123                      struct T<'i> {
1124                        #[schemars(rename = "property", schema_with = "property")]
1125                        _property: &'i u8,
1126                        #[schemars(rename = "vendorPrefix")]
1127                        _vendor_prefix: VendorPrefix,
1128                        #[schemars(rename = "value")]
1129                        _value: $type,
1130                      }
1131
1132                      T::json_schema(gen)
1133                    }};
1134                    () => {{
1135                      #[derive(schemars::JsonSchema)]
1136                      struct T<'i> {
1137                        #[schemars(rename = "property", schema_with = "property")]
1138                        _property: &'i u8,
1139                        #[schemars(rename = "value")]
1140                        _value: $type,
1141                      }
1142
1143                      T::json_schema(gen)
1144                    }};
1145                  }
1146
1147                  with_prefix!($($vp)?)
1148                },
1149              )+
1150              {
1151                property!("all");
1152                #[derive(schemars::JsonSchema)]
1153                struct T {
1154                  #[schemars(rename = "property", schema_with = "property")]
1155                  _property: u8,
1156                  #[schemars(rename = "value")]
1157                  _value: CSSWideKeyword
1158                }
1159                T::json_schema(gen)
1160              },
1161              {
1162                property!("unparsed");
1163
1164                #[derive(schemars::JsonSchema)]
1165                struct T<'i> {
1166                  #[schemars(rename = "property", schema_with = "property")]
1167                  _property: &'i u8,
1168                  #[schemars(rename = "value")]
1169                  _value: UnparsedProperty<'i>,
1170                }
1171
1172                T::json_schema(gen)
1173              },
1174              {
1175                property!("custom");
1176
1177                #[derive(schemars::JsonSchema)]
1178                struct T<'i> {
1179                  #[schemars(rename = "property", schema_with = "property")]
1180                  _property: &'i u8,
1181                  #[schemars(rename = "value")]
1182                  _value: CustomProperty<'i>,
1183                }
1184
1185                T::json_schema(gen)
1186              }
1187            ]),
1188            ..Default::default()
1189          })),
1190          ..Default::default()
1191        })
1192      }
1193
1194      fn schema_name() -> String {
1195        "Declaration".into()
1196      }
1197    }
1198  };
1199}
1200
1201define_properties! {
1202  "background-color": BackgroundColor(CssColor),
1203  "background-image": BackgroundImage(SmallVec<[Image<'i>; 1]>),
1204  "background-position-x": BackgroundPositionX(SmallVec<[HorizontalPosition; 1]>),
1205  "background-position-y": BackgroundPositionY(SmallVec<[VerticalPosition; 1]>),
1206  "background-position": BackgroundPosition(SmallVec<[BackgroundPosition; 1]>) shorthand: true,
1207  "background-size": BackgroundSize(SmallVec<[BackgroundSize; 1]>),
1208  "background-repeat": BackgroundRepeat(SmallVec<[BackgroundRepeat; 1]>),
1209  "background-attachment": BackgroundAttachment(SmallVec<[BackgroundAttachment; 1]>),
1210  "background-clip": BackgroundClip(SmallVec<[BackgroundClip; 1]>, VendorPrefix) / WebKit / Moz,
1211  "background-origin": BackgroundOrigin(SmallVec<[BackgroundOrigin; 1]>),
1212  "background": Background(SmallVec<[Background<'i>; 1]>) shorthand: true,
1213
1214  "box-shadow": BoxShadow(SmallVec<[BoxShadow; 1]>, VendorPrefix) / WebKit / Moz,
1215  "opacity": Opacity(AlphaValue),
1216  "color": Color(CssColor),
1217  "display": Display(Display),
1218  "visibility": Visibility(Visibility),
1219
1220  "width": Width(Size) [logical_group: Size, category: Physical],
1221  "height": Height(Size) [logical_group: Size, category: Physical],
1222  "min-width": MinWidth(Size) [logical_group: MinSize, category: Physical],
1223  "min-height": MinHeight(Size) [logical_group: MinSize, category: Physical],
1224  "max-width": MaxWidth(MaxSize) [logical_group: MaxSize, category: Physical],
1225  "max-height": MaxHeight(MaxSize) [logical_group: MaxSize, category: Physical],
1226  "block-size": BlockSize(Size) [logical_group: Size, category: Logical],
1227  "inline-size": InlineSize(Size) [logical_group: Size, category: Logical],
1228  "min-block-size": MinBlockSize(Size) [logical_group: MinSize, category: Logical],
1229  "min-inline-size": MinInlineSize(Size) [logical_group: MinSize, category: Logical],
1230  "max-block-size": MaxBlockSize(MaxSize) [logical_group: MaxSize, category: Logical],
1231  "max-inline-size": MaxInlineSize(MaxSize) [logical_group: MaxSize, category: Logical],
1232  "box-sizing": BoxSizing(BoxSizing, VendorPrefix) / WebKit / Moz,
1233  "aspect-ratio": AspectRatio(AspectRatio),
1234
1235  "overflow": Overflow(Overflow) shorthand: true,
1236  "overflow-x": OverflowX(OverflowKeyword),
1237  "overflow-y": OverflowY(OverflowKeyword),
1238  "text-overflow": TextOverflow(TextOverflow, VendorPrefix) / O,
1239
1240  // https://www.w3.org/TR/2020/WD-css-position-3-20200519
1241  "position": Position(position::Position),
1242  "top": Top(LengthPercentageOrAuto) [logical_group: Inset, category: Physical],
1243  "bottom": Bottom(LengthPercentageOrAuto) [logical_group: Inset, category: Physical],
1244  "left": Left(LengthPercentageOrAuto) [logical_group: Inset, category: Physical],
1245  "right": Right(LengthPercentageOrAuto) [logical_group: Inset, category: Physical],
1246  "inset-block-start": InsetBlockStart(LengthPercentageOrAuto) [logical_group: Inset, category: Logical],
1247  "inset-block-end": InsetBlockEnd(LengthPercentageOrAuto) [logical_group: Inset, category: Logical],
1248  "inset-inline-start": InsetInlineStart(LengthPercentageOrAuto) [logical_group: Inset, category: Logical],
1249  "inset-inline-end": InsetInlineEnd(LengthPercentageOrAuto) [logical_group: Inset, category: Logical],
1250  "inset-block": InsetBlock(InsetBlock) shorthand: true,
1251  "inset-inline": InsetInline(InsetInline) shorthand: true,
1252  "inset": Inset(Inset) shorthand: true,
1253
1254  "border-spacing": BorderSpacing(Size2D<Length>),
1255
1256  "border-top-color": BorderTopColor(CssColor) [logical_group: BorderColor, category: Physical],
1257  "border-bottom-color": BorderBottomColor(CssColor) [logical_group: BorderColor, category: Physical],
1258  "border-left-color": BorderLeftColor(CssColor) [logical_group: BorderColor, category: Physical],
1259  "border-right-color": BorderRightColor(CssColor) [logical_group: BorderColor, category: Physical],
1260  "border-block-start-color": BorderBlockStartColor(CssColor) [logical_group: BorderColor, category: Logical],
1261  "border-block-end-color": BorderBlockEndColor(CssColor) [logical_group: BorderColor, category: Logical],
1262  "border-inline-start-color": BorderInlineStartColor(CssColor) [logical_group: BorderColor, category: Logical],
1263  "border-inline-end-color": BorderInlineEndColor(CssColor) [logical_group: BorderColor, category: Logical],
1264
1265  "border-top-style": BorderTopStyle(LineStyle) [logical_group: BorderStyle, category: Physical],
1266  "border-bottom-style": BorderBottomStyle(LineStyle) [logical_group: BorderStyle, category: Physical],
1267  "border-left-style": BorderLeftStyle(LineStyle) [logical_group: BorderStyle, category: Physical],
1268  "border-right-style": BorderRightStyle(LineStyle) [logical_group: BorderStyle, category: Physical],
1269  "border-block-start-style": BorderBlockStartStyle(LineStyle) [logical_group: BorderStyle, category: Logical],
1270  "border-block-end-style": BorderBlockEndStyle(LineStyle) [logical_group: BorderStyle, category: Logical],
1271  "border-inline-start-style": BorderInlineStartStyle(LineStyle) [logical_group: BorderStyle, category: Logical],
1272  "border-inline-end-style": BorderInlineEndStyle(LineStyle) [logical_group: BorderStyle, category: Logical],
1273
1274  "border-top-width": BorderTopWidth(BorderSideWidth) [logical_group: BorderWidth, category: Physical],
1275  "border-bottom-width": BorderBottomWidth(BorderSideWidth) [logical_group: BorderWidth, category: Physical],
1276  "border-left-width": BorderLeftWidth(BorderSideWidth) [logical_group: BorderWidth, category: Physical],
1277  "border-right-width": BorderRightWidth(BorderSideWidth) [logical_group: BorderWidth, category: Physical],
1278  "border-block-start-width": BorderBlockStartWidth(BorderSideWidth) [logical_group: BorderWidth, category: Logical],
1279  "border-block-end-width": BorderBlockEndWidth(BorderSideWidth) [logical_group: BorderWidth, category: Logical],
1280  "border-inline-start-width": BorderInlineStartWidth(BorderSideWidth) [logical_group: BorderWidth, category: Logical],
1281  "border-inline-end-width": BorderInlineEndWidth(BorderSideWidth) [logical_group: BorderWidth, category: Logical],
1282
1283  "border-top-left-radius": BorderTopLeftRadius(Size2D<LengthPercentage>, VendorPrefix) / WebKit / Moz [logical_group: BorderRadius, category: Physical],
1284  "border-top-right-radius": BorderTopRightRadius(Size2D<LengthPercentage>, VendorPrefix) / WebKit / Moz [logical_group: BorderRadius, category: Physical],
1285  "border-bottom-left-radius": BorderBottomLeftRadius(Size2D<LengthPercentage>, VendorPrefix) / WebKit / Moz [logical_group: BorderRadius, category: Physical],
1286  "border-bottom-right-radius": BorderBottomRightRadius(Size2D<LengthPercentage>, VendorPrefix) / WebKit / Moz [logical_group: BorderRadius, category: Physical],
1287  "border-start-start-radius": BorderStartStartRadius(Size2D<LengthPercentage>) [logical_group: BorderRadius, category: Logical],
1288  "border-start-end-radius": BorderStartEndRadius(Size2D<LengthPercentage>) [logical_group: BorderRadius, category: Logical],
1289  "border-end-start-radius": BorderEndStartRadius(Size2D<LengthPercentage>) [logical_group: BorderRadius, category: Logical],
1290  "border-end-end-radius": BorderEndEndRadius(Size2D<LengthPercentage>) [logical_group: BorderRadius, category: Logical],
1291  "border-radius": BorderRadius(BorderRadius, VendorPrefix) / WebKit / Moz shorthand: true,
1292
1293  "border-image-source": BorderImageSource(Image<'i>),
1294  "border-image-outset": BorderImageOutset(Rect<LengthOrNumber>),
1295  "border-image-repeat": BorderImageRepeat(BorderImageRepeat),
1296  "border-image-width": BorderImageWidth(Rect<BorderImageSideWidth>),
1297  "border-image-slice": BorderImageSlice(BorderImageSlice),
1298  "border-image": BorderImage(BorderImage<'i>, VendorPrefix) / WebKit / Moz / O shorthand: true,
1299
1300  "border-color": BorderColor(BorderColor) shorthand: true,
1301  "border-style": BorderStyle(BorderStyle) shorthand: true,
1302  "border-width": BorderWidth(BorderWidth) shorthand: true,
1303
1304  "border-block-color": BorderBlockColor(BorderBlockColor) shorthand: true,
1305  "border-block-style": BorderBlockStyle(BorderBlockStyle) shorthand: true,
1306  "border-block-width": BorderBlockWidth(BorderBlockWidth) shorthand: true,
1307
1308  "border-inline-color": BorderInlineColor(BorderInlineColor) shorthand: true,
1309  "border-inline-style": BorderInlineStyle(BorderInlineStyle) shorthand: true,
1310  "border-inline-width": BorderInlineWidth(BorderInlineWidth) shorthand: true,
1311
1312  "border": Border(Border) shorthand: true,
1313  "border-top": BorderTop(BorderTop) shorthand: true,
1314  "border-bottom": BorderBottom(BorderBottom) shorthand: true,
1315  "border-left": BorderLeft(BorderLeft) shorthand: true,
1316  "border-right": BorderRight(BorderRight) shorthand: true,
1317  "border-block": BorderBlock(BorderBlock) shorthand: true,
1318  "border-block-start": BorderBlockStart(BorderBlockStart) shorthand: true,
1319  "border-block-end": BorderBlockEnd(BorderBlockEnd) shorthand: true,
1320  "border-inline": BorderInline(BorderInline) shorthand: true,
1321  "border-inline-start": BorderInlineStart(BorderInlineStart) shorthand: true,
1322  "border-inline-end": BorderInlineEnd(BorderInlineEnd) shorthand: true,
1323
1324  "outline": Outline(Outline) shorthand: true,
1325  "outline-color": OutlineColor(CssColor),
1326  "outline-style": OutlineStyle(OutlineStyle),
1327  "outline-width": OutlineWidth(BorderSideWidth),
1328
1329  // Flex properties: https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119
1330  "flex-direction": FlexDirection(FlexDirection, VendorPrefix) / WebKit / Ms,
1331  "flex-wrap": FlexWrap(FlexWrap, VendorPrefix) / WebKit / Ms,
1332  "flex-flow": FlexFlow(FlexFlow, VendorPrefix) / WebKit / Ms shorthand: true,
1333  "flex-grow": FlexGrow(CSSNumber, VendorPrefix) / WebKit,
1334  "flex-shrink": FlexShrink(CSSNumber, VendorPrefix) / WebKit,
1335  "flex-basis": FlexBasis(LengthPercentageOrAuto, VendorPrefix) / WebKit,
1336  "flex": Flex(Flex, VendorPrefix) / WebKit / Ms shorthand: true,
1337  "order": Order(CSSInteger, VendorPrefix) / WebKit,
1338
1339  // Align properties: https://www.w3.org/TR/2020/WD-css-align-3-20200421
1340  "align-content": AlignContent(AlignContent, VendorPrefix) / WebKit,
1341  "justify-content": JustifyContent(JustifyContent, VendorPrefix) / WebKit,
1342  "place-content": PlaceContent(PlaceContent) shorthand: true,
1343  "align-self": AlignSelf(AlignSelf, VendorPrefix) / WebKit,
1344  "justify-self": JustifySelf(JustifySelf),
1345  "place-self": PlaceSelf(PlaceSelf) shorthand: true,
1346  "align-items": AlignItems(AlignItems, VendorPrefix) / WebKit,
1347  "justify-items": JustifyItems(JustifyItems),
1348  "place-items": PlaceItems(PlaceItems) shorthand: true,
1349  "row-gap": RowGap(GapValue),
1350  "column-gap": ColumnGap(GapValue),
1351  "gap": Gap(Gap) shorthand: true,
1352
1353  // Old flex (2009): https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/
1354  "box-orient": BoxOrient(BoxOrient, VendorPrefix) / WebKit / Moz unprefixed: false,
1355  "box-direction": BoxDirection(BoxDirection, VendorPrefix) / WebKit / Moz unprefixed: false,
1356  "box-ordinal-group": BoxOrdinalGroup(CSSInteger, VendorPrefix) / WebKit / Moz unprefixed: false,
1357  "box-align": BoxAlign(BoxAlign, VendorPrefix) / WebKit / Moz unprefixed: false,
1358  "box-flex": BoxFlex(CSSNumber, VendorPrefix) / WebKit / Moz unprefixed: false,
1359  "box-flex-group": BoxFlexGroup(CSSInteger, VendorPrefix) / WebKit unprefixed: false,
1360  "box-pack": BoxPack(BoxPack, VendorPrefix) / WebKit / Moz unprefixed: false,
1361  "box-lines": BoxLines(BoxLines, VendorPrefix) / WebKit / Moz unprefixed: false,
1362
1363  // Old flex (2012): https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/
1364  "flex-pack": FlexPack(FlexPack, VendorPrefix) / Ms unprefixed: false,
1365  "flex-order": FlexOrder(CSSInteger, VendorPrefix) / Ms unprefixed: false,
1366  "flex-align": FlexAlign(BoxAlign, VendorPrefix) / Ms unprefixed: false,
1367  "flex-item-align": FlexItemAlign(FlexItemAlign, VendorPrefix) / Ms unprefixed: false,
1368  "flex-line-pack": FlexLinePack(FlexLinePack, VendorPrefix) / Ms unprefixed: false,
1369
1370  // Microsoft extensions
1371  "flex-positive": FlexPositive(CSSNumber, VendorPrefix) / Ms unprefixed: false,
1372  "flex-negative": FlexNegative(CSSNumber, VendorPrefix) / Ms unprefixed: false,
1373  "flex-preferred-size": FlexPreferredSize(LengthPercentageOrAuto, VendorPrefix) / Ms unprefixed: false,
1374
1375  #[cfg(feature = "grid")]
1376  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1377  "grid-template-columns": GridTemplateColumns(TrackSizing<'i>),
1378  #[cfg(feature = "grid")]
1379  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1380  "grid-template-rows": GridTemplateRows(TrackSizing<'i>),
1381  #[cfg(feature = "grid")]
1382  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1383  "grid-auto-columns": GridAutoColumns(TrackSizeList),
1384  #[cfg(feature = "grid")]
1385  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1386  "grid-auto-rows": GridAutoRows(TrackSizeList),
1387  #[cfg(feature = "grid")]
1388  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1389  "grid-auto-flow": GridAutoFlow(GridAutoFlow),
1390  #[cfg(feature = "grid")]
1391  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1392  "grid-template-areas": GridTemplateAreas(GridTemplateAreas),
1393  #[cfg(feature = "grid")]
1394  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1395  "grid-template": GridTemplate(GridTemplate<'i>) shorthand: true,
1396  #[cfg(feature = "grid")]
1397  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1398  "grid": Grid(Grid<'i>) shorthand: true,
1399  #[cfg(feature = "grid")]
1400  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1401  "grid-row-start": GridRowStart(GridLine<'i>),
1402  #[cfg(feature = "grid")]
1403  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1404  "grid-row-end": GridRowEnd(GridLine<'i>),
1405  #[cfg(feature = "grid")]
1406  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1407  "grid-column-start": GridColumnStart(GridLine<'i>),
1408  #[cfg(feature = "grid")]
1409  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1410  "grid-column-end": GridColumnEnd(GridLine<'i>),
1411  #[cfg(feature = "grid")]
1412  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1413  "grid-row": GridRow(GridRow<'i>) shorthand: true,
1414  #[cfg(feature = "grid")]
1415  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1416  "grid-column": GridColumn(GridColumn<'i>) shorthand: true,
1417  #[cfg(feature = "grid")]
1418  #[cfg_attr(docsrs, doc(cfg(feature = "grid")))]
1419  "grid-area": GridArea(GridArea<'i>) shorthand: true,
1420
1421  "margin-top": MarginTop(LengthPercentageOrAuto) [logical_group: Margin, category: Physical],
1422  "margin-bottom": MarginBottom(LengthPercentageOrAuto) [logical_group: Margin, category: Physical],
1423  "margin-left": MarginLeft(LengthPercentageOrAuto) [logical_group: Margin, category: Physical],
1424  "margin-right": MarginRight(LengthPercentageOrAuto) [logical_group: Margin, category: Physical],
1425  "margin-block-start": MarginBlockStart(LengthPercentageOrAuto) [logical_group: Margin, category: Logical],
1426  "margin-block-end": MarginBlockEnd(LengthPercentageOrAuto) [logical_group: Margin, category: Logical],
1427  "margin-inline-start": MarginInlineStart(LengthPercentageOrAuto) [logical_group: Margin, category: Logical],
1428  "margin-inline-end": MarginInlineEnd(LengthPercentageOrAuto) [logical_group: Margin, category: Logical],
1429  "margin-block": MarginBlock(MarginBlock) shorthand: true,
1430  "margin-inline": MarginInline(MarginInline) shorthand: true,
1431  "margin": Margin(Margin) shorthand: true,
1432
1433  "padding-top": PaddingTop(LengthPercentageOrAuto) [logical_group: Padding, category: Physical],
1434  "padding-bottom": PaddingBottom(LengthPercentageOrAuto) [logical_group: Padding, category: Physical],
1435  "padding-left": PaddingLeft(LengthPercentageOrAuto) [logical_group: Padding, category: Physical],
1436  "padding-right": PaddingRight(LengthPercentageOrAuto) [logical_group: Padding, category: Physical],
1437  "padding-block-start": PaddingBlockStart(LengthPercentageOrAuto) [logical_group: Padding, category: Logical],
1438  "padding-block-end": PaddingBlockEnd(LengthPercentageOrAuto) [logical_group: Padding, category: Logical],
1439  "padding-inline-start": PaddingInlineStart(LengthPercentageOrAuto) [logical_group: Padding, category: Logical],
1440  "padding-inline-end": PaddingInlineEnd(LengthPercentageOrAuto) [logical_group: Padding, category: Logical],
1441  "padding-block": PaddingBlock(PaddingBlock) shorthand: true,
1442  "padding-inline": PaddingInline(PaddingInline) shorthand: true,
1443  "padding": Padding(Padding) shorthand: true,
1444
1445  "scroll-margin-top": ScrollMarginTop(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Physical],
1446  "scroll-margin-bottom": ScrollMarginBottom(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Physical],
1447  "scroll-margin-left": ScrollMarginLeft(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Physical],
1448  "scroll-margin-right": ScrollMarginRight(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Physical],
1449  "scroll-margin-block-start": ScrollMarginBlockStart(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Logical],
1450  "scroll-margin-block-end": ScrollMarginBlockEnd(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Logical],
1451  "scroll-margin-inline-start": ScrollMarginInlineStart(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Logical],
1452  "scroll-margin-inline-end": ScrollMarginInlineEnd(LengthPercentageOrAuto) [logical_group: ScrollMargin, category: Logical],
1453  "scroll-margin-block": ScrollMarginBlock(ScrollMarginBlock) shorthand: true,
1454  "scroll-margin-inline": ScrollMarginInline(ScrollMarginInline) shorthand: true,
1455  "scroll-margin": ScrollMargin(ScrollMargin) shorthand: true,
1456
1457  "scroll-padding-top": ScrollPaddingTop(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Physical],
1458  "scroll-padding-bottom": ScrollPaddingBottom(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Physical],
1459  "scroll-padding-left": ScrollPaddingLeft(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Physical],
1460  "scroll-padding-right": ScrollPaddingRight(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Physical],
1461  "scroll-padding-block-start": ScrollPaddingBlockStart(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Logical],
1462  "scroll-padding-block-end": ScrollPaddingBlockEnd(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Logical],
1463  "scroll-padding-inline-start": ScrollPaddingInlineStart(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Logical],
1464  "scroll-padding-inline-end": ScrollPaddingInlineEnd(LengthPercentageOrAuto) [logical_group: ScrollPadding, category: Logical],
1465  "scroll-padding-block": ScrollPaddingBlock(ScrollPaddingBlock) shorthand: true,
1466  "scroll-padding-inline": ScrollPaddingInline(ScrollPaddingInline) shorthand: true,
1467  "scroll-padding": ScrollPadding(ScrollPadding) shorthand: true,
1468
1469  "font-weight": FontWeight(FontWeight),
1470  "font-size": FontSize(FontSize),
1471  "font-stretch": FontStretch(FontStretch),
1472  "font-family": FontFamily(Vec<FontFamily<'i>>),
1473  "font-style": FontStyle(FontStyle),
1474  "font-variant-caps": FontVariantCaps(FontVariantCaps),
1475  "line-height": LineHeight(LineHeight),
1476  "font": Font(Font<'i>) shorthand: true,
1477  "vertical-align": VerticalAlign(VerticalAlign),
1478  "font-palette": FontPalette(DashedIdentReference<'i>),
1479
1480  "transition-property": TransitionProperty(SmallVec<[PropertyId<'i>; 1]>, VendorPrefix) / WebKit / Moz / Ms,
1481  "transition-duration": TransitionDuration(SmallVec<[Time; 1]>, VendorPrefix) / WebKit / Moz / Ms,
1482  "transition-delay": TransitionDelay(SmallVec<[Time; 1]>, VendorPrefix) / WebKit / Moz / Ms,
1483  "transition-timing-function": TransitionTimingFunction(SmallVec<[EasingFunction; 1]>, VendorPrefix) / WebKit / Moz / Ms,
1484  "transition": Transition(SmallVec<[Transition<'i>; 1]>, VendorPrefix) / WebKit / Moz / Ms shorthand: true,
1485
1486  "animation-name": AnimationName(AnimationNameList<'i>, VendorPrefix) / WebKit / Moz / O,
1487  "animation-duration": AnimationDuration(SmallVec<[Time; 1]>, VendorPrefix) / WebKit / Moz / O,
1488  "animation-timing-function": AnimationTimingFunction(SmallVec<[EasingFunction; 1]>, VendorPrefix) / WebKit / Moz / O,
1489  "animation-iteration-count": AnimationIterationCount(SmallVec<[AnimationIterationCount; 1]>, VendorPrefix) / WebKit / Moz / O,
1490  "animation-direction": AnimationDirection(SmallVec<[AnimationDirection; 1]>, VendorPrefix) / WebKit / Moz / O,
1491  "animation-play-state": AnimationPlayState(SmallVec<[AnimationPlayState; 1]>, VendorPrefix) / WebKit / Moz / O,
1492  "animation-delay": AnimationDelay(SmallVec<[Time; 1]>, VendorPrefix) / WebKit / Moz / O,
1493  "animation-fill-mode": AnimationFillMode(SmallVec<[AnimationFillMode; 1]>, VendorPrefix) / WebKit / Moz / O,
1494  "animation-composition": AnimationComposition(SmallVec<[AnimationComposition; 1]>),
1495  "animation-timeline": AnimationTimeline(SmallVec<[AnimationTimeline<'i>; 1]>),
1496  "animation-range-start": AnimationRangeStart(SmallVec<[AnimationRangeStart; 1]>),
1497  "animation-range-end": AnimationRangeEnd(SmallVec<[AnimationRangeEnd; 1]>),
1498  "animation-range": AnimationRange(SmallVec<[AnimationRange; 1]>),
1499  "animation": Animation(AnimationList<'i>, VendorPrefix) / WebKit / Moz / O shorthand: true,
1500
1501  // https://drafts.csswg.org/css-transforms-2/
1502  "transform": Transform(TransformList, VendorPrefix) / WebKit / Moz / Ms / O,
1503  "transform-origin": TransformOrigin(Position, VendorPrefix) / WebKit / Moz / Ms / O, // TODO: handle z offset syntax
1504  "transform-style": TransformStyle(TransformStyle, VendorPrefix) / WebKit / Moz,
1505  "transform-box": TransformBox(TransformBox),
1506  "backface-visibility": BackfaceVisibility(BackfaceVisibility, VendorPrefix) / WebKit / Moz,
1507  "perspective": Perspective(Perspective, VendorPrefix) / WebKit / Moz,
1508  "perspective-origin": PerspectiveOrigin(Position, VendorPrefix) / WebKit / Moz,
1509  "translate": Translate(Translate),
1510  "rotate": Rotate(Rotate),
1511  "scale": Scale(Scale),
1512
1513  // https://www.w3.org/TR/2021/CRD-css-text-3-20210422
1514  "text-transform": TextTransform(TextTransform),
1515  "white-space": WhiteSpace(WhiteSpace),
1516  "tab-size": TabSize(LengthOrNumber, VendorPrefix) / Moz / O,
1517  "word-break": WordBreak(WordBreak),
1518  "line-break": LineBreak(LineBreak),
1519  "hyphens": Hyphens(Hyphens, VendorPrefix) / WebKit / Moz / Ms,
1520  "overflow-wrap": OverflowWrap(OverflowWrap),
1521  "word-wrap": WordWrap(OverflowWrap),
1522  "text-align": TextAlign(TextAlign),
1523  "text-align-last": TextAlignLast(TextAlignLast, VendorPrefix) / Moz,
1524  "text-justify": TextJustify(TextJustify),
1525  "word-spacing": WordSpacing(Spacing),
1526  "letter-spacing": LetterSpacing(Spacing),
1527  "text-indent": TextIndent(TextIndent),
1528
1529  // https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506
1530  "text-decoration-line": TextDecorationLine(TextDecorationLine, VendorPrefix) / WebKit / Moz,
1531  "text-decoration-style": TextDecorationStyle(TextDecorationStyle, VendorPrefix) / WebKit / Moz,
1532  "text-decoration-color": TextDecorationColor(CssColor, VendorPrefix) / WebKit / Moz,
1533  "text-decoration-thickness": TextDecorationThickness(TextDecorationThickness),
1534  "text-decoration": TextDecoration(TextDecoration, VendorPrefix) / WebKit / Moz shorthand: true,
1535  "text-decoration-skip-ink": TextDecorationSkipInk(TextDecorationSkipInk, VendorPrefix) / WebKit,
1536  "text-emphasis-style": TextEmphasisStyle(TextEmphasisStyle<'i>, VendorPrefix) / WebKit,
1537  "text-emphasis-color": TextEmphasisColor(CssColor, VendorPrefix) / WebKit,
1538  "text-emphasis": TextEmphasis(TextEmphasis<'i>, VendorPrefix) / WebKit shorthand: true,
1539  "text-emphasis-position": TextEmphasisPosition(TextEmphasisPosition, VendorPrefix) / WebKit,
1540  "text-shadow": TextShadow(SmallVec<[TextShadow; 1]>),
1541
1542  // https://w3c.github.io/csswg-drafts/css-size-adjust/
1543  "text-size-adjust": TextSizeAdjust(TextSizeAdjust, VendorPrefix) / WebKit / Moz / Ms,
1544
1545  // https://drafts.csswg.org/css-writing-modes-3/
1546  "direction": Direction(Direction),
1547  "unicode-bidi": UnicodeBidi(UnicodeBidi),
1548
1549  // https://www.w3.org/TR/css-break-3/
1550  "box-decoration-break": BoxDecorationBreak(BoxDecorationBreak, VendorPrefix) / WebKit,
1551
1552  // https://www.w3.org/TR/2021/WD-css-ui-4-20210316
1553  "resize": Resize(Resize),
1554  "cursor": Cursor(Cursor<'i>),
1555  "caret-color": CaretColor(ColorOrAuto),
1556  "caret-shape": CaretShape(CaretShape),
1557  "caret": Caret(Caret) shorthand: true,
1558  "user-select": UserSelect(UserSelect, VendorPrefix) / WebKit / Moz / Ms,
1559  "accent-color": AccentColor(ColorOrAuto),
1560  "appearance": Appearance(Appearance<'i>, VendorPrefix) / WebKit / Moz / Ms,
1561
1562  // https://www.w3.org/TR/2020/WD-css-lists-3-20201117
1563  "list-style-type": ListStyleType(ListStyleType<'i>),
1564  "list-style-image": ListStyleImage(Image<'i>),
1565  "list-style-position": ListStylePosition(ListStylePosition),
1566  "list-style": ListStyle(ListStyle<'i>) shorthand: true,
1567  "marker-side": MarkerSide(MarkerSide),
1568
1569  // CSS modules
1570  "composes": Composes(Composes<'i>) if css_modules,
1571
1572  // https://www.w3.org/TR/SVG2/painting.html
1573  "fill": Fill(SVGPaint<'i>),
1574  "fill-rule": FillRule(FillRule),
1575  "fill-opacity": FillOpacity(AlphaValue),
1576  "stroke": Stroke(SVGPaint<'i>),
1577  "stroke-opacity": StrokeOpacity(AlphaValue),
1578  "stroke-width": StrokeWidth(LengthPercentage),
1579  "stroke-linecap": StrokeLinecap(StrokeLinecap),
1580  "stroke-linejoin": StrokeLinejoin(StrokeLinejoin),
1581  "stroke-miterlimit": StrokeMiterlimit(CSSNumber),
1582  "stroke-dasharray": StrokeDasharray(StrokeDasharray),
1583  "stroke-dashoffset": StrokeDashoffset(LengthPercentage),
1584  "marker-start": MarkerStart(Marker<'i>),
1585  "marker-mid": MarkerMid(Marker<'i>),
1586  "marker-end": MarkerEnd(Marker<'i>),
1587  "marker": Marker(Marker<'i>),
1588  "color-interpolation": ColorInterpolation(ColorInterpolation),
1589  "color-interpolation-filters": ColorInterpolationFilters(ColorInterpolation),
1590  "color-rendering": ColorRendering(ColorRendering),
1591  "shape-rendering": ShapeRendering(ShapeRendering),
1592  "text-rendering": TextRendering(TextRendering),
1593  "image-rendering": ImageRendering(ImageRendering),
1594
1595  // https://www.w3.org/TR/css-masking-1/
1596  "clip-path": ClipPath(ClipPath<'i>, VendorPrefix) / WebKit,
1597  "clip-rule": ClipRule(FillRule),
1598  "mask-image": MaskImage(SmallVec<[Image<'i>; 1]>, VendorPrefix) / WebKit,
1599  "mask-mode": MaskMode(SmallVec<[MaskMode; 1]>),
1600  "mask-repeat": MaskRepeat(SmallVec<[BackgroundRepeat; 1]>, VendorPrefix) / WebKit,
1601  "mask-position-x": MaskPositionX(SmallVec<[HorizontalPosition; 1]>),
1602  "mask-position-y": MaskPositionY(SmallVec<[VerticalPosition; 1]>),
1603  "mask-position": MaskPosition(SmallVec<[Position; 1]>, VendorPrefix) / WebKit,
1604  "mask-clip": MaskClip(SmallVec<[MaskClip; 1]>, VendorPrefix) / WebKit,
1605  "mask-origin": MaskOrigin(SmallVec<[GeometryBox; 1]>, VendorPrefix) / WebKit,
1606  "mask-size": MaskSize(SmallVec<[BackgroundSize; 1]>, VendorPrefix) / WebKit,
1607  "mask-composite": MaskComposite(SmallVec<[MaskComposite; 1]>),
1608  "mask-type": MaskType(MaskType),
1609  "mask": Mask(SmallVec<[Mask<'i>; 1]>, VendorPrefix) / WebKit shorthand: true,
1610  "mask-border-source": MaskBorderSource(Image<'i>),
1611  "mask-border-mode": MaskBorderMode(MaskBorderMode),
1612  "mask-border-slice": MaskBorderSlice(BorderImageSlice),
1613  "mask-border-width": MaskBorderWidth(Rect<BorderImageSideWidth>),
1614  "mask-border-outset": MaskBorderOutset(Rect<LengthOrNumber>),
1615  "mask-border-repeat": MaskBorderRepeat(BorderImageRepeat),
1616  "mask-border": MaskBorder(MaskBorder<'i>) shorthand: true,
1617
1618  // WebKit additions
1619  "-webkit-mask-composite": WebKitMaskComposite(SmallVec<[WebKitMaskComposite; 1]>),
1620  "mask-source-type": WebKitMaskSourceType(SmallVec<[WebKitMaskSourceType; 1]>, VendorPrefix) / WebKit unprefixed: false,
1621  "mask-box-image": WebKitMaskBoxImage(BorderImage<'i>, VendorPrefix) / WebKit unprefixed: false,
1622  "mask-box-image-source": WebKitMaskBoxImageSource(Image<'i>, VendorPrefix) / WebKit unprefixed: false,
1623  "mask-box-image-slice": WebKitMaskBoxImageSlice(BorderImageSlice, VendorPrefix) / WebKit unprefixed: false,
1624  "mask-box-image-width": WebKitMaskBoxImageWidth(Rect<BorderImageSideWidth>, VendorPrefix) / WebKit unprefixed: false,
1625  "mask-box-image-outset": WebKitMaskBoxImageOutset(Rect<LengthOrNumber>, VendorPrefix) / WebKit unprefixed: false,
1626  "mask-box-image-repeat": WebKitMaskBoxImageRepeat(BorderImageRepeat, VendorPrefix) / WebKit unprefixed: false,
1627
1628  // https://drafts.fxtf.org/filter-effects-1/
1629  "filter": Filter(FilterList<'i>, VendorPrefix) / WebKit,
1630  "backdrop-filter": BackdropFilter(FilterList<'i>, VendorPrefix) / WebKit,
1631
1632  // https://drafts.csswg.org/css2/
1633  "z-index": ZIndex(position::ZIndex),
1634
1635  // https://drafts.csswg.org/css-contain-3/
1636  "container-type": ContainerType(ContainerType),
1637  "container-name": ContainerName(ContainerNameList<'i>),
1638  "container": Container(Container<'i>) shorthand: true,
1639
1640  // https://w3c.github.io/csswg-drafts/css-view-transitions-1/
1641  "view-transition-name": ViewTransitionName(ViewTransitionName<'i>),
1642  // https://drafts.csswg.org/css-view-transitions-2/
1643  "view-transition-class": ViewTransitionClass(NoneOrCustomIdentList<'i>),
1644  "view-transition-group": ViewTransitionGroup(ViewTransitionGroup<'i>),
1645
1646  // https://drafts.csswg.org/css-color-adjust/
1647  "color-scheme": ColorScheme(ColorScheme),
1648}
1649
1650impl<'i, T: smallvec::Array<Item = V>, V: Parse<'i>> Parse<'i> for SmallVec<T> {
1651  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
1652    // Copied from cssparser `parse_comma_separated` but using SmallVec instead of Vec.
1653    let mut values = smallvec![];
1654    loop {
1655      input.skip_whitespace(); // Unnecessary for correctness, but may help try() in parse_one rewind less.
1656      match input.parse_until_before(Delimiter::Comma, &mut V::parse) {
1657        Ok(v) => values.push(v),
1658        Err(err) => return Err(err),
1659      }
1660      match input.next() {
1661        Err(_) => return Ok(values),
1662        Ok(&cssparser::Token::Comma) => continue,
1663        Ok(_) => unreachable!(),
1664      }
1665    }
1666  }
1667}
1668
1669impl<T: smallvec::Array<Item = V>, V: ToCss> ToCss for SmallVec<T> {
1670  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
1671  where
1672    W: std::fmt::Write,
1673  {
1674    let len = self.len();
1675    for (idx, val) in self.iter().enumerate() {
1676      val.to_css(dest)?;
1677      if idx < len - 1 {
1678        dest.delim(',', false)?;
1679      }
1680    }
1681    Ok(())
1682  }
1683}
1684
1685impl<'i, T: Parse<'i>> Parse<'i> for Vec<T> {
1686  fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
1687    input.parse_comma_separated(|input| T::parse(input))
1688  }
1689}
1690
1691impl<T: ToCss> ToCss for Vec<T> {
1692  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
1693  where
1694    W: std::fmt::Write,
1695  {
1696    let len = self.len();
1697    for (idx, val) in self.iter().enumerate() {
1698      val.to_css(dest)?;
1699      if idx < len - 1 {
1700        dest.delim(',', false)?;
1701      }
1702    }
1703    Ok(())
1704  }
1705}
1706
1707enum_property! {
1708  /// A [CSS-wide keyword](https://drafts.csswg.org/css-cascade-5/#defaulting-keywords).
1709  pub enum CSSWideKeyword {
1710    /// The property's initial value.
1711    "initial": Initial,
1712    /// The property's computed value on the parent element.
1713    "inherit": Inherit,
1714    /// Either inherit or initial depending on whether the property is inherited.
1715    "unset": Unset,
1716    /// Rolls back the cascade to the cascaded value of the earlier origin.
1717    "revert": Revert,
1718    /// Rolls back the cascade to the value of the previous cascade layer.
1719    "revert-layer": RevertLayer,
1720  }
1721}