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