Skip to main content

lightningcss/
declaration.rs

1//! CSS declarations.
2
3use std::borrow::Cow;
4use std::ops::Range;
5
6use crate::context::{DeclarationContext, PropertyHandlerContext};
7use crate::error::{ParserError, PrinterError, PrinterErrorKind};
8use crate::parser::ParserOptions;
9use crate::printer::Printer;
10use crate::properties::box_shadow::BoxShadowHandler;
11use crate::properties::custom::{CustomProperty, CustomPropertyName};
12use crate::properties::masking::MaskHandler;
13use crate::properties::text::{Direction, UnicodeBidi};
14use crate::properties::{
15  align::AlignHandler,
16  animation::AnimationHandler,
17  background::BackgroundHandler,
18  border::BorderHandler,
19  contain::ContainerHandler,
20  display::DisplayHandler,
21  flex::FlexHandler,
22  font::FontHandler,
23  grid::GridHandler,
24  list::ListStyleHandler,
25  margin_padding::*,
26  outline::OutlineHandler,
27  overflow::OverflowHandler,
28  position::PositionHandler,
29  prefix_handler::{FallbackHandler, PrefixHandler},
30  size::SizeHandler,
31  text::TextDecorationHandler,
32  transform::TransformHandler,
33  transition::TransitionHandler,
34  ui::ColorSchemeHandler,
35};
36use crate::properties::{Property, PropertyId};
37use crate::selector::SelectorList;
38use crate::traits::{PropertyHandler, ToCss};
39use crate::values::ident::DashedIdent;
40use crate::values::string::CowArcStr;
41#[cfg(feature = "visitor")]
42use crate::visitor::Visit;
43use cssparser::*;
44use indexmap::IndexMap;
45use smallvec::SmallVec;
46
47/// A CSS declaration block.
48///
49/// Properties are separated into a list of `!important` declararations,
50/// and a list of normal declarations. This reduces memory usage compared
51/// with storing a boolean along with each property.
52#[derive(Debug, PartialEq, Clone, Default)]
53#[cfg_attr(feature = "visitor", derive(Visit), visit(visit_declaration_block, PROPERTIES))]
54#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
55#[cfg_attr(
56  feature = "serde",
57  derive(serde::Serialize, serde::Deserialize),
58  serde(rename_all = "camelCase")
59)]
60#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
61pub struct DeclarationBlock<'i> {
62  /// A list of `!important` declarations in the block.
63  #[cfg_attr(feature = "serde", serde(borrow, default))]
64  pub important_declarations: Vec<Property<'i>>,
65  /// A list of normal declarations in the block.
66  #[cfg_attr(feature = "serde", serde(default))]
67  pub declarations: Vec<Property<'i>>,
68}
69
70impl<'i> DeclarationBlock<'i> {
71  /// Parses a declaration block from CSS syntax.
72  pub fn parse<'a, 't>(
73    input: &mut Parser<'i, 't>,
74    options: &'a ParserOptions<'i>,
75  ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
76    let mut important_declarations = DeclarationList::new();
77    let mut declarations = DeclarationList::new();
78    let mut decl_parser = PropertyDeclarationParser {
79      important_declarations: &mut important_declarations,
80      declarations: &mut declarations,
81      options,
82    };
83    let mut parser = RuleBodyParser::new(input, &mut decl_parser);
84    while let Some(res) = parser.next() {
85      if let Err((err, _)) = res {
86        if options.error_recovery {
87          options.warn(err);
88          continue;
89        }
90        return Err(err);
91      }
92    }
93
94    Ok(DeclarationBlock {
95      important_declarations,
96      declarations,
97    })
98  }
99
100  /// Parses a declaration block from a string.
101  pub fn parse_string<'o>(
102    input: &'i str,
103    options: ParserOptions<'i>,
104  ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
105    let mut input = ParserInput::new(input);
106    let mut parser = Parser::new(&mut input);
107    let result = Self::parse(&mut parser, &options)?;
108    parser.expect_exhausted()?;
109    Ok(result)
110  }
111
112  /// Returns an empty declaration block.
113  pub fn new() -> Self {
114    Self {
115      declarations: vec![],
116      important_declarations: vec![],
117    }
118  }
119
120  /// Returns the total number of declarations in the block.
121  pub fn len(&self) -> usize {
122    self.declarations.len() + self.important_declarations.len()
123  }
124}
125
126impl<'i> ToCss for DeclarationBlock<'i> {
127  fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
128  where
129    W: std::fmt::Write,
130  {
131    let len = self.declarations.len() + self.important_declarations.len();
132    let mut i = 0;
133
134    macro_rules! write {
135      ($decls: expr, $important: literal) => {
136        for decl in &$decls {
137          decl.to_css(dest, $important)?;
138          if i != len - 1 {
139            dest.write_char(';')?;
140            dest.whitespace()?;
141          }
142          i += 1;
143        }
144      };
145    }
146
147    write!(self.declarations, false);
148    write!(self.important_declarations, true);
149    Ok(())
150  }
151}
152
153impl<'i> DeclarationBlock<'i> {
154  /// Writes the declarations to a CSS block, including starting and ending braces.
155  pub fn to_css_block<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
156  where
157    W: std::fmt::Write,
158  {
159    dest.whitespace()?;
160    dest.write_char('{')?;
161    dest.indent();
162    dest.newline()?;
163
164    self.to_css_declarations(dest, false, &parcel_selectors::SelectorList(SmallVec::new()), 0)?;
165
166    dest.dedent();
167    dest.newline()?;
168    dest.write_char('}')
169  }
170
171  pub(crate) fn has_printable_declarations(&self) -> bool {
172    if self.len() > 1 {
173      return true;
174    }
175
176    if self.declarations.len() == 1 {
177      !matches!(self.declarations[0], crate::properties::Property::Composes(_))
178    } else if self.important_declarations.len() == 1 {
179      !matches!(self.important_declarations[0], crate::properties::Property::Composes(_))
180    } else {
181      false
182    }
183  }
184
185  /// Writes the declarations to a CSS declaration block.
186  pub fn to_css_declarations<W>(
187    &self,
188    dest: &mut Printer<W>,
189    has_nested_rules: bool,
190    selectors: &SelectorList,
191    source_index: u32,
192  ) -> Result<(), PrinterError>
193  where
194    W: std::fmt::Write,
195  {
196    let mut i = 0;
197    let len = self.len();
198
199    macro_rules! write {
200      ($decls: expr, $important: literal) => {
201        for decl in &$decls {
202          // The CSS modules `composes` property is handled specially, and omitted during printing.
203          // We need to add the classes it references to the list for the selectors in this rule.
204          if let crate::properties::Property::Composes(composes) = &decl {
205            if dest.is_nested() && dest.css_module.is_some() {
206              return Err(dest.error(PrinterErrorKind::InvalidComposesNesting, composes.loc));
207            }
208
209            if let Some(css_module) = &mut dest.css_module {
210              css_module
211                .handle_composes(&selectors, &composes, source_index)
212                .map_err(|e| dest.error(e, composes.loc))?;
213              continue;
214            }
215          }
216
217          if i > 0 {
218            dest.newline()?;
219          }
220
221          decl.to_css(dest, $important)?;
222          if i != len - 1 || !dest.minify || has_nested_rules {
223            dest.write_char(';')?;
224          }
225
226          i += 1;
227        }
228      };
229    }
230
231    write!(self.declarations, false);
232    write!(self.important_declarations, true);
233    Ok(())
234  }
235}
236
237impl<'i> DeclarationBlock<'i> {
238  pub(crate) fn minify(
239    &mut self,
240    handler: &mut DeclarationHandler<'i>,
241    important_handler: &mut DeclarationHandler<'i>,
242    context: &mut PropertyHandlerContext<'i, '_>,
243  ) {
244    macro_rules! handle {
245      ($decls: expr, $handler: expr, $important: literal) => {
246        for decl in $decls.iter() {
247          context.is_important = $important;
248          let handled = $handler.handle_property(decl, context);
249
250          if !handled {
251            $handler.decls.push(decl.clone());
252          }
253        }
254      };
255    }
256
257    handle!(self.important_declarations, important_handler, true);
258    handle!(self.declarations, handler, false);
259
260    handler.finalize(context);
261    important_handler.finalize(context);
262    self.important_declarations = std::mem::take(&mut important_handler.decls);
263    self.declarations = std::mem::take(&mut handler.decls);
264  }
265
266  /// Returns whether the declaration block is empty.
267  pub fn is_empty(&self) -> bool {
268    return self.declarations.is_empty() && self.important_declarations.is_empty();
269  }
270
271  pub(crate) fn property_location<'t>(
272    &self,
273    input: &mut Parser<'i, 't>,
274    index: usize,
275  ) -> Result<(Range<SourceLocation>, Range<SourceLocation>), ParseError<'i, ParserError<'i>>> {
276    // Skip to the requested property index.
277    for _ in 0..index {
278      input.expect_ident()?;
279      input.expect_colon()?;
280      input.parse_until_after(Delimiter::Semicolon, |parser| {
281        while parser.next().is_ok() {}
282        Ok(())
283      })?;
284    }
285
286    // Get property name range.
287    input.skip_whitespace();
288    let key_start = input.current_source_location();
289    input.expect_ident()?;
290    let key_end = input.current_source_location();
291    let key_range = key_start..key_end;
292
293    input.expect_colon()?;
294    input.skip_whitespace();
295
296    // Get value range.
297    let val_start = input.current_source_location();
298    input.parse_until_before(Delimiter::Semicolon, |parser| {
299      while parser.next().is_ok() {}
300      Ok(())
301    })?;
302    let val_end = input.current_source_location();
303    let val_range = val_start..val_end;
304
305    Ok((key_range, val_range))
306  }
307}
308
309impl<'i> DeclarationBlock<'i> {
310  /// Returns an iterator over all properties in the declaration.
311  pub fn iter(&self) -> impl std::iter::DoubleEndedIterator<Item = (&Property<'i>, bool)> {
312    self
313      .declarations
314      .iter()
315      .map(|property| (property, false))
316      .chain(self.important_declarations.iter().map(|property| (property, true)))
317  }
318
319  /// Returns a mutable iterator over all properties in the declaration.
320  pub fn iter_mut(&mut self) -> impl std::iter::DoubleEndedIterator<Item = &mut Property<'i>> {
321    self.declarations.iter_mut().chain(self.important_declarations.iter_mut())
322  }
323
324  /// Returns the value for a given property id based on the properties in this declaration block.
325  ///
326  /// If the property is a shorthand, the result will be a combined value of all of the included
327  /// longhands, or `None` if some of the longhands are not declared. Otherwise, the value will be
328  /// either an explicitly declared longhand, or a value extracted from a shorthand property.
329  pub fn get<'a>(&'a self, property_id: &PropertyId) -> Option<(Cow<'a, Property<'i>>, bool)> {
330    if property_id.is_shorthand() {
331      if let Some((shorthand, important)) = property_id.shorthand_value(&self) {
332        return Some((Cow::Owned(shorthand), important));
333      }
334    } else {
335      for (property, important) in self.iter().rev() {
336        if property.property_id() == *property_id {
337          return Some((Cow::Borrowed(property), important));
338        }
339
340        if let Some(val) = property.longhand(&property_id) {
341          return Some((Cow::Owned(val), important));
342        }
343      }
344    }
345
346    None
347  }
348
349  /// Sets the value and importance for a given property, replacing any existing declarations.
350  ///
351  /// If the property already exists within the declaration block, it is updated in place. Otherwise,
352  /// a new declaration is appended. When updating a longhand property and a shorthand is defined which
353  /// includes the longhand, the shorthand will be updated rather than appending a new declaration.
354  pub fn set(&mut self, property: Property<'i>, important: bool) {
355    let property_id = property.property_id();
356    let declarations = if important {
357      // Remove any non-important properties with this id.
358      self.declarations.retain(|decl| decl.property_id() != property_id);
359      &mut self.important_declarations
360    } else {
361      // Remove any important properties with this id.
362      self.important_declarations.retain(|decl| decl.property_id() != property_id);
363      &mut self.declarations
364    };
365
366    let longhands = property_id.longhands().unwrap_or_else(|| vec![property.property_id()]);
367
368    for decl in declarations.iter_mut().rev() {
369      {
370        // If any of the longhands being set are in the same logical property group as any of the
371        // longhands in this property, but in a different category (i.e. logical or physical),
372        // then we cannot modify in place, and need to append a new property.
373        let id = decl.property_id();
374        let id_longhands = id.longhands().unwrap_or_else(|| vec![id]);
375        if longhands.iter().any(|longhand| {
376          let logical_group = longhand.logical_group();
377          let category = longhand.category();
378
379          logical_group.is_some()
380            && id_longhands.iter().any(|id_longhand| {
381              logical_group == id_longhand.logical_group() && category != id_longhand.category()
382            })
383        }) {
384          break;
385        }
386      }
387
388      if decl.property_id() == property_id {
389        *decl = property;
390        return;
391      }
392
393      // Update shorthand.
394      if decl.set_longhand(&property).is_ok() {
395        return;
396      }
397    }
398
399    declarations.push(property)
400  }
401
402  /// Removes all declarations of the given property id from the declaration block.
403  ///
404  /// When removing a longhand property and a shorthand is defined which includes the longhand,
405  /// the shorthand will be split apart into its component longhand properties, minus the property
406  /// to remove. When removing a shorthand, all included longhand properties are also removed.
407  pub fn remove(&mut self, property_id: &PropertyId) {
408    fn remove<'i, 'a>(declarations: &mut Vec<Property<'i>>, property_id: &PropertyId<'a>) {
409      let longhands = property_id.longhands().unwrap_or(vec![]);
410      let mut i = 0;
411      while i < declarations.len() {
412        let replacement = {
413          let property = &declarations[i];
414          let id = property.property_id();
415          if id == *property_id || longhands.contains(&id) {
416            // If the property matches the requested property id, or is a longhand
417            // property that is included in the requested shorthand, remove it.
418            None
419          } else if longhands.is_empty() && id.longhands().unwrap_or(vec![]).contains(&property_id) {
420            // If this is a shorthand property that includes the requested longhand,
421            // split it apart into its component longhands, excluding the requested one.
422            Some(
423              id.longhands()
424                .unwrap()
425                .iter()
426                .filter_map(|longhand| {
427                  if *longhand == *property_id {
428                    None
429                  } else {
430                    property.longhand(longhand)
431                  }
432                })
433                .collect::<Vec<Property>>(),
434            )
435          } else {
436            i += 1;
437            continue;
438          }
439        };
440
441        match replacement {
442          Some(properties) => {
443            let count = properties.len();
444            declarations.splice(i..i + 1, properties);
445            i += count;
446          }
447          None => {
448            declarations.remove(i);
449          }
450        }
451      }
452    }
453
454    remove(&mut self.declarations, property_id);
455    remove(&mut self.important_declarations, property_id);
456  }
457}
458
459struct PropertyDeclarationParser<'a, 'i> {
460  important_declarations: &'a mut Vec<Property<'i>>,
461  declarations: &'a mut Vec<Property<'i>>,
462  options: &'a ParserOptions<'i>,
463}
464
465/// Parse a declaration within {} block: `color: blue`
466impl<'a, 'i> cssparser::DeclarationParser<'i> for PropertyDeclarationParser<'a, 'i> {
467  type Declaration = ();
468  type Error = ParserError<'i>;
469
470  fn parse_value<'t>(
471    &mut self,
472    name: CowRcStr<'i>,
473    input: &mut cssparser::Parser<'i, 't>,
474    _declaration_start: &ParserState,
475  ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
476    parse_declaration(
477      name,
478      input,
479      &mut self.declarations,
480      &mut self.important_declarations,
481      &self.options,
482    )
483  }
484}
485
486/// Default methods reject all at rules.
487impl<'a, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'i> {
488  type Prelude = ();
489  type AtRule = ();
490  type Error = ParserError<'i>;
491}
492
493impl<'a, 'i> QualifiedRuleParser<'i> for PropertyDeclarationParser<'a, 'i> {
494  type Prelude = ();
495  type QualifiedRule = ();
496  type Error = ParserError<'i>;
497}
498
499impl<'a, 'i> RuleBodyItemParser<'i, (), ParserError<'i>> for PropertyDeclarationParser<'a, 'i> {
500  fn parse_qualified(&self) -> bool {
501    false
502  }
503
504  fn parse_declarations(&self) -> bool {
505    true
506  }
507}
508
509pub(crate) fn parse_declaration<'i, 't>(
510  name: CowRcStr<'i>,
511  input: &mut cssparser::Parser<'i, 't>,
512  declarations: &mut DeclarationList<'i>,
513  important_declarations: &mut DeclarationList<'i>,
514  options: &ParserOptions<'i>,
515) -> Result<(), cssparser::ParseError<'i, ParserError<'i>>> {
516  // Stop if we hit a `{` token in a non-custom property to
517  // avoid ambiguity between nested rules and declarations.
518  // https://github.com/w3c/csswg-drafts/issues/9317
519  let property_id = PropertyId::from(CowArcStr::from(name));
520  let mut delimiters = Delimiter::Bang;
521  if !matches!(property_id, PropertyId::Custom(CustomPropertyName::Custom(..))) {
522    delimiters = delimiters | Delimiter::CurlyBracketBlock;
523  }
524  let property = input.parse_until_before(delimiters, |input| Property::parse(property_id, input, options))?;
525  let important = input
526    .try_parse(|input| {
527      input.expect_delim('!')?;
528      input.expect_ident_matching("important")
529    })
530    .is_ok();
531  input.expect_exhausted()?;
532  if important {
533    important_declarations.push(property);
534  } else {
535    declarations.push(property);
536  }
537  Ok(())
538}
539
540pub(crate) type DeclarationList<'i> = Vec<Property<'i>>;
541
542#[derive(Default)]
543pub(crate) struct DeclarationHandler<'i> {
544  background: BackgroundHandler<'i>,
545  border: BorderHandler<'i>,
546  outline: OutlineHandler,
547  flex: FlexHandler,
548  grid: GridHandler<'i>,
549  align: AlignHandler,
550  size: SizeHandler,
551  margin: MarginHandler<'i>,
552  padding: PaddingHandler<'i>,
553  scroll_margin: ScrollMarginHandler<'i>,
554  scroll_padding: ScrollPaddingHandler<'i>,
555  font: FontHandler<'i>,
556  text: TextDecorationHandler<'i>,
557  list: ListStyleHandler<'i>,
558  transition: TransitionHandler<'i>,
559  animation: AnimationHandler<'i>,
560  display: DisplayHandler<'i>,
561  position: PositionHandler,
562  inset: InsetHandler<'i>,
563  overflow: OverflowHandler,
564  transform: TransformHandler,
565  box_shadow: BoxShadowHandler,
566  mask: MaskHandler<'i>,
567  container: ContainerHandler<'i>,
568  color_scheme: ColorSchemeHandler,
569  fallback: FallbackHandler,
570  prefix: PrefixHandler,
571  direction: Option<Direction>,
572  unicode_bidi: Option<UnicodeBidi>,
573  custom_properties: IndexMap<DashedIdent<'i>, usize>,
574  decls: DeclarationList<'i>,
575}
576
577impl<'i> DeclarationHandler<'i> {
578  pub fn handle_property(
579    &mut self,
580    property: &Property<'i>,
581    context: &mut PropertyHandlerContext<'i, '_>,
582  ) -> bool {
583    self.background.handle_property(property, &mut self.decls, context)
584      || self.border.handle_property(property, &mut self.decls, context)
585      || self.outline.handle_property(property, &mut self.decls, context)
586      || self.flex.handle_property(property, &mut self.decls, context)
587      || self.grid.handle_property(property, &mut self.decls, context)
588      || self.align.handle_property(property, &mut self.decls, context)
589      || self.size.handle_property(property, &mut self.decls, context)
590      || self.margin.handle_property(property, &mut self.decls, context)
591      || self.padding.handle_property(property, &mut self.decls, context)
592      || self.scroll_margin.handle_property(property, &mut self.decls, context)
593      || self.scroll_padding.handle_property(property, &mut self.decls, context)
594      || self.font.handle_property(property, &mut self.decls, context)
595      || self.text.handle_property(property, &mut self.decls, context)
596      || self.list.handle_property(property, &mut self.decls, context)
597      || self.transition.handle_property(property, &mut self.decls, context)
598      || self.animation.handle_property(property, &mut self.decls, context)
599      || self.display.handle_property(property, &mut self.decls, context)
600      || self.position.handle_property(property, &mut self.decls, context)
601      || self.inset.handle_property(property, &mut self.decls, context)
602      || self.overflow.handle_property(property, &mut self.decls, context)
603      || self.transform.handle_property(property, &mut self.decls, context)
604      || self.box_shadow.handle_property(property, &mut self.decls, context)
605      || self.mask.handle_property(property, &mut self.decls, context)
606      || self.container.handle_property(property, &mut self.decls, context)
607      || self.color_scheme.handle_property(property, &mut self.decls, context)
608      || self.fallback.handle_property(property, &mut self.decls, context)
609      || self.prefix.handle_property(property, &mut self.decls, context)
610      || self.handle_all(property)
611      || self.handle_custom_property(property, context)
612  }
613
614  fn handle_custom_property(
615    &mut self,
616    property: &Property<'i>,
617    context: &mut PropertyHandlerContext<'i, '_>,
618  ) -> bool {
619    if let Property::Custom(custom) = property {
620      if context.unused_symbols.contains(custom.name.as_ref()) {
621        return true;
622      }
623
624      if let CustomPropertyName::Custom(name) = &custom.name {
625        if let Some(index) = self.custom_properties.get(name) {
626          if self.decls[*index] == *property {
627            return true;
628          }
629          let mut custom = custom.clone();
630          self.add_conditional_fallbacks(&mut custom, context);
631          self.decls[*index] = Property::Custom(custom);
632        } else {
633          self.custom_properties.insert(name.clone(), self.decls.len());
634          let mut custom = custom.clone();
635          self.add_conditional_fallbacks(&mut custom, context);
636          self.decls.push(Property::Custom(custom));
637        }
638
639        return true;
640      }
641    }
642
643    false
644  }
645
646  fn handle_all(&mut self, property: &Property<'i>) -> bool {
647    // The `all` property resets all properies except `unicode-bidi`, `direction`, and custom properties.
648    // https://drafts.csswg.org/css-cascade-5/#all-shorthand
649    match property {
650      Property::UnicodeBidi(bidi) => {
651        self.unicode_bidi = Some(*bidi);
652        true
653      }
654      Property::Direction(direction) => {
655        self.direction = Some(*direction);
656        true
657      }
658      Property::All(keyword) => {
659        let mut handler = DeclarationHandler {
660          unicode_bidi: self.unicode_bidi.clone(),
661          direction: self.direction.clone(),
662          ..Default::default()
663        };
664        for (key, index) in self.custom_properties.drain(..) {
665          handler.custom_properties.insert(key, handler.decls.len());
666          handler.decls.push(self.decls[index].clone());
667        }
668        handler.decls.push(Property::All(keyword.clone()));
669        *self = handler;
670        true
671      }
672      _ => false,
673    }
674  }
675
676  fn add_conditional_fallbacks(
677    &self,
678    custom: &mut CustomProperty<'i>,
679    context: &mut PropertyHandlerContext<'i, '_>,
680  ) {
681    if context.context != DeclarationContext::Keyframes {
682      let fallbacks = custom.value.get_fallbacks(context.targets);
683      for (condition, fallback) in fallbacks {
684        context.add_conditional_property(
685          condition,
686          Property::Custom(CustomProperty {
687            name: custom.name.clone(),
688            value: fallback,
689          }),
690        );
691      }
692    }
693  }
694
695  pub fn finalize(&mut self, context: &mut PropertyHandlerContext<'i, '_>) {
696    if let Some(direction) = std::mem::take(&mut self.direction) {
697      self.decls.push(Property::Direction(direction));
698    }
699    if let Some(unicode_bidi) = std::mem::take(&mut self.unicode_bidi) {
700      self.decls.push(Property::UnicodeBidi(unicode_bidi));
701    }
702
703    self.background.finalize(&mut self.decls, context);
704    self.border.finalize(&mut self.decls, context);
705    self.outline.finalize(&mut self.decls, context);
706    self.flex.finalize(&mut self.decls, context);
707    self.grid.finalize(&mut self.decls, context);
708    self.align.finalize(&mut self.decls, context);
709    self.size.finalize(&mut self.decls, context);
710    self.margin.finalize(&mut self.decls, context);
711    self.padding.finalize(&mut self.decls, context);
712    self.scroll_margin.finalize(&mut self.decls, context);
713    self.scroll_padding.finalize(&mut self.decls, context);
714    self.font.finalize(&mut self.decls, context);
715    self.text.finalize(&mut self.decls, context);
716    self.list.finalize(&mut self.decls, context);
717    self.transition.finalize(&mut self.decls, context);
718    self.animation.finalize(&mut self.decls, context);
719    self.display.finalize(&mut self.decls, context);
720    self.position.finalize(&mut self.decls, context);
721    self.inset.finalize(&mut self.decls, context);
722    self.overflow.finalize(&mut self.decls, context);
723    self.transform.finalize(&mut self.decls, context);
724    self.box_shadow.finalize(&mut self.decls, context);
725    self.mask.finalize(&mut self.decls, context);
726    self.container.finalize(&mut self.decls, context);
727    self.color_scheme.finalize(&mut self.decls, context);
728    self.fallback.finalize(&mut self.decls, context);
729    self.prefix.finalize(&mut self.decls, context);
730    self.custom_properties.clear();
731  }
732}