Skip to main content

style/properties/
declaration_block.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! A property declaration block.
6
7#![deny(missing_docs)]
8
9use super::{
10    AllShorthand, ComputedValues, LogicalGroupSet, LonghandIdSet, LonghandIdSetIterator,
11    NonCustomPropertyId, NonCustomPropertyIdSet, PropertyDeclaration, PropertyDeclarationId,
12    PropertyId, ShorthandId, SourcePropertyDeclaration, SourcePropertyDeclarationDrain,
13    SubpropertiesVec, property_counts,
14};
15
16use crate::context::{QuirksMode, TreeCountingCaches};
17use crate::custom_properties;
18use crate::derives::*;
19use crate::dom::{AttributeTracker, DummyElementContext};
20use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
21use crate::parser::ParserContext;
22use crate::properties::{
23    StyleBuilder,
24    animated_properties::{AnimationValue, AnimationValueMap},
25};
26use crate::rule_cache::RuleCacheConditions;
27use crate::rule_tree::RuleCascadeFlags;
28use crate::selector_map::PrecomputedHashSet;
29use crate::selector_parser::SelectorImpl;
30use crate::shared_lock::Locked;
31use crate::stylesheets::container_rule::ContainerSizeQuery;
32use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
33use crate::stylist::Stylist;
34use crate::typed_om::TypedValueList;
35use crate::values::computed::Context;
36use cssparser::{
37    AtRuleParser, CowRcStr, DeclarationParser, Delimiter, ParseErrorKind, Parser, ParserState,
38    QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, parse_important,
39};
40use itertools::Itertools;
41use selectors::SelectorList;
42use servo_arc::Arc;
43use smallbitvec::SmallBitVec;
44use smallvec::SmallVec;
45use std::borrow::Cow;
46use std::fmt::{self, Write};
47use std::iter::Zip;
48use std::slice::Iter;
49use std::sync::atomic::AtomicBool;
50use style_traits::{
51    CssString, CssStringWriter, CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss,
52};
53use thin_vec::ThinVec;
54
55/// A set of property declarations including animations and transitions.
56#[derive(Default)]
57pub struct AnimationDeclarations {
58    /// Declarations for animations.
59    pub animations: Option<Arc<Locked<PropertyDeclarationBlock>>>,
60    /// Declarations for transitions.
61    pub transitions: Option<Arc<Locked<PropertyDeclarationBlock>>>,
62}
63
64impl AnimationDeclarations {
65    /// Whether or not this `AnimationDeclarations` is empty.
66    pub fn is_empty(&self) -> bool {
67        self.animations.is_none() && self.transitions.is_none()
68    }
69}
70
71/// An enum describes how a declaration should update
72/// the declaration block.
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74enum DeclarationUpdate {
75    /// The given declaration doesn't update anything.
76    None,
77    /// The given declaration is new, and should be append directly.
78    Append,
79    /// The given declaration can be updated in-place at the given position.
80    UpdateInPlace { pos: usize },
81    /// The given declaration cannot be updated in-place, and an existing
82    /// one needs to be removed at the given position.
83    AppendAndRemove { pos: usize },
84}
85
86/// A struct describes how a declaration block should be updated by
87/// a `SourcePropertyDeclaration`.
88#[derive(Default)]
89pub struct SourcePropertyDeclarationUpdate {
90    updates: SubpropertiesVec<DeclarationUpdate>,
91    new_count: usize,
92    any_removal: bool,
93}
94
95/// A declaration [importance][importance].
96///
97/// [importance]: https://drafts.csswg.org/css-cascade/#importance
98#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, Default)]
99pub enum Importance {
100    /// Indicates a declaration without `!important`.
101    #[default]
102    Normal,
103
104    /// Indicates a declaration with `!important`.
105    Important,
106}
107
108impl Importance {
109    /// Return whether this is an important declaration.
110    pub fn important(self) -> bool {
111        match self {
112            Self::Normal => false,
113            Self::Important => true,
114        }
115    }
116}
117
118/// A set of properties.
119#[derive(Clone, Debug, ToShmem, Default, MallocSizeOf)]
120pub struct PropertyDeclarationIdSet {
121    longhands: LonghandIdSet,
122    custom: PrecomputedHashSet<custom_properties::Name>,
123}
124
125impl PropertyDeclarationIdSet {
126    /// Add the given property to the set.
127    pub fn insert(&mut self, id: PropertyDeclarationId) -> bool {
128        match id {
129            PropertyDeclarationId::Longhand(id) => {
130                if self.longhands.contains(id) {
131                    return false;
132                }
133                self.longhands.insert(id);
134                true
135            },
136            PropertyDeclarationId::Custom(name) => self.custom.insert((*name).clone()),
137        }
138    }
139
140    /// Return whether the given property is in the set.
141    pub fn contains(&self, id: PropertyDeclarationId) -> bool {
142        match id {
143            PropertyDeclarationId::Longhand(id) => self.longhands.contains(id),
144            PropertyDeclarationId::Custom(name) => self.custom.contains(name),
145        }
146    }
147
148    /// Remove the given property from the set.
149    pub fn remove(&mut self, id: PropertyDeclarationId) {
150        match id {
151            PropertyDeclarationId::Longhand(id) => self.longhands.remove(id),
152            PropertyDeclarationId::Custom(name) => {
153                self.custom.remove(name);
154            },
155        }
156    }
157
158    /// Remove all properties from the set.
159    pub fn clear(&mut self) {
160        self.longhands.clear();
161        self.custom.clear();
162    }
163
164    /// Returns whether the set is empty.
165    #[inline]
166    pub fn is_empty(&self) -> bool {
167        self.longhands.is_empty() && self.custom.is_empty()
168    }
169    /// Returns whether this set contains any reset longhand.
170    #[inline]
171    pub fn contains_any_reset(&self) -> bool {
172        self.longhands.contains_any_reset()
173    }
174
175    /// Returns whether this set contains all longhands in the specified set.
176    #[inline]
177    pub fn contains_all_longhands(&self, longhands: &LonghandIdSet) -> bool {
178        self.longhands.contains_all(longhands)
179    }
180
181    /// Returns whether this set contains all properties in the specified set.
182    #[inline]
183    pub fn contains_all(&self, properties: &PropertyDeclarationIdSet) -> bool {
184        if !self.longhands.contains_all(&properties.longhands) {
185            return false;
186        }
187        if properties.custom.len() > self.custom.len() {
188            return false;
189        }
190        properties
191            .custom
192            .iter()
193            .all(|item| self.custom.contains(item))
194    }
195
196    /// Iterate over the current property declaration id set.
197    pub fn iter(&self) -> PropertyDeclarationIdSetIterator<'_> {
198        PropertyDeclarationIdSetIterator {
199            longhands: self.longhands.iter(),
200            custom: self.custom.iter(),
201        }
202    }
203}
204
205/// An iterator over a set of longhand ids.
206pub struct PropertyDeclarationIdSetIterator<'a> {
207    longhands: LonghandIdSetIterator<'a>,
208    custom: hashbrown::hash_set::Iter<'a, custom_properties::Name>,
209}
210
211impl<'a> Iterator for PropertyDeclarationIdSetIterator<'a> {
212    type Item = PropertyDeclarationId<'a>;
213
214    fn next(&mut self) -> Option<Self::Item> {
215        // LonghandIdSetIterator's implementation always returns None
216        // after it did it once, so the code below will then continue
217        // to iterate over the custom properties.
218        match self.longhands.next() {
219            Some(id) => Some(PropertyDeclarationId::Longhand(id)),
220            None => self.custom.next().map(PropertyDeclarationId::Custom),
221        }
222    }
223}
224
225/// Overridden declarations are skipped.
226#[derive(Default, MallocSizeOf)]
227pub struct PropertyDeclarationBlock {
228    /// The group of declarations, along with their importance.
229    ///
230    /// Only deduplicated declarations appear here.
231    declarations: ThinVec<PropertyDeclaration>,
232
233    /// The "important" flag for each declaration in `declarations`.
234    declarations_importance: SmallBitVec,
235
236    /// The set of properties that are present in the block.
237    property_ids: PropertyDeclarationIdSet,
238
239    /// Whether this declaration block may be mutated by CSSOM without copying.
240    /// Set when a declaration is shared across elements and needs to be copied, even when not in
241    /// the rule tree, e.g. via the style attribute or the XUL prototype caches.
242    pub immutable: AtomicBool,
243}
244
245impl to_shmem::ToShmem for PropertyDeclarationBlock {
246    fn to_shmem(&self, builder: &mut to_shmem::SharedMemoryBuilder) -> to_shmem::Result<Self> {
247        use std::mem::ManuallyDrop;
248        let declarations = self.declarations.to_shmem(builder)?;
249        let declarations_importance = self.declarations_importance.to_shmem(builder)?;
250        let property_ids = self.property_ids.to_shmem(builder)?;
251        let immutable = AtomicBool::new(true);
252
253        Ok(ManuallyDrop::new(Self {
254            declarations: ManuallyDrop::into_inner(declarations),
255            declarations_importance: ManuallyDrop::into_inner(declarations_importance),
256            property_ids: ManuallyDrop::into_inner(property_ids),
257            immutable,
258        }))
259    }
260}
261
262impl Clone for PropertyDeclarationBlock {
263    fn clone(&self) -> Self {
264        Self {
265            declarations: self.declarations.clone(),
266            declarations_importance: self.declarations_importance.clone(),
267            property_ids: self.property_ids.clone(),
268            immutable: AtomicBool::new(false),
269        }
270    }
271}
272
273impl PartialEq for PropertyDeclarationBlock {
274    fn eq(&self, other: &Self) -> bool {
275        // property_ids must be equal if declarations are equal, so we don't
276        // need to compare them explicitly.
277        // immutable doesn't matter for equality either.
278        self.declarations == other.declarations
279            && self.declarations_importance == other.declarations_importance
280    }
281}
282
283/// Iterator over `(PropertyDeclaration, Importance)` pairs.
284pub struct DeclarationImportanceIterator<'a> {
285    iter: Zip<Iter<'a, PropertyDeclaration>, smallbitvec::Iter<'a>>,
286}
287
288impl<'a> Default for DeclarationImportanceIterator<'a> {
289    fn default() -> Self {
290        Self {
291            iter: [].iter().zip(smallbitvec::Iter::default()),
292        }
293    }
294}
295
296impl<'a> DeclarationImportanceIterator<'a> {
297    /// Constructor.
298    fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
299        DeclarationImportanceIterator {
300            iter: declarations.iter().zip(important.iter()),
301        }
302    }
303}
304
305impl<'a> Iterator for DeclarationImportanceIterator<'a> {
306    type Item = (&'a PropertyDeclaration, Importance);
307
308    #[inline]
309    fn next(&mut self) -> Option<Self::Item> {
310        self.iter.next().map(|(decl, important)| {
311            (
312                decl,
313                if important {
314                    Importance::Important
315                } else {
316                    Importance::Normal
317                },
318            )
319        })
320    }
321
322    #[inline]
323    fn size_hint(&self) -> (usize, Option<usize>) {
324        self.iter.size_hint()
325    }
326}
327
328impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
329    #[inline(always)]
330    fn next_back(&mut self) -> Option<Self::Item> {
331        self.iter.next_back().map(|(decl, important)| {
332            (
333                decl,
334                if important {
335                    Importance::Important
336                } else {
337                    Importance::Normal
338                },
339            )
340        })
341    }
342}
343
344/// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
345pub struct AnimationValueIterator<'a, 'cx, 'cx_a: 'cx> {
346    iter: DeclarationImportanceIterator<'a>,
347    context: &'cx mut Context<'cx_a>,
348    style: &'a ComputedValues,
349    default_values: &'a ComputedValues,
350}
351
352impl<'a, 'cx, 'cx_a: 'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
353    fn new(
354        declarations: &'a PropertyDeclarationBlock,
355        context: &'cx mut Context<'cx_a>,
356        style: &'a ComputedValues,
357        default_values: &'a ComputedValues,
358    ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
359        AnimationValueIterator {
360            iter: declarations.declaration_importance_iter(),
361            context,
362            style,
363            default_values,
364        }
365    }
366}
367
368impl<'a, 'cx, 'cx_a: 'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
369    type Item = AnimationValue;
370    #[inline]
371    fn next(&mut self) -> Option<Self::Item> {
372        loop {
373            let (decl, importance) = self.iter.next()?;
374
375            if importance.important() {
376                continue;
377            }
378
379            let animation = AnimationValue::from_declaration(
380                decl,
381                self.context,
382                self.style,
383                self.default_values,
384                // TODO (descalante): should be able to get an attr from an animated element
385                &mut AttributeTracker::new_dummy(),
386            );
387
388            if let Some(anim) = animation {
389                return Some(anim);
390            }
391        }
392    }
393}
394
395impl fmt::Debug for PropertyDeclarationBlock {
396    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397        self.declarations.fmt(f)
398    }
399}
400
401impl PropertyDeclarationBlock {
402    /// Returns the number of declarations in the block.
403    #[inline]
404    pub fn len(&self) -> usize {
405        self.declarations.len()
406    }
407
408    /// Returns whether the block is empty.
409    #[inline]
410    pub fn is_empty(&self) -> bool {
411        self.declarations.is_empty()
412    }
413
414    /// Create an empty block
415    #[inline]
416    pub fn new() -> Self {
417        PropertyDeclarationBlock {
418            declarations: ThinVec::new(),
419            declarations_importance: SmallBitVec::new(),
420            property_ids: PropertyDeclarationIdSet::default(),
421            immutable: AtomicBool::new(false),
422        }
423    }
424
425    /// Create a block with a single declaration
426    pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
427        let mut property_ids = PropertyDeclarationIdSet::default();
428        property_ids.insert(declaration.id());
429        let mut declarations = ThinVec::with_capacity(1);
430        declarations.push(declaration);
431        PropertyDeclarationBlock {
432            declarations,
433            declarations_importance: SmallBitVec::from_elem(1, importance.important()),
434            property_ids,
435            immutable: AtomicBool::new(false),
436        }
437    }
438
439    /// The declarations in this block
440    #[inline]
441    pub fn declarations(&self) -> &[PropertyDeclaration] {
442        &self.declarations
443    }
444
445    /// The `important` flags for declarations in this block
446    #[inline]
447    pub fn declarations_importance(&self) -> &SmallBitVec {
448        &self.declarations_importance
449    }
450
451    /// Iterate over `(PropertyDeclaration, Importance)` pairs
452    #[inline]
453    pub fn declaration_importance_iter(&self) -> DeclarationImportanceIterator<'_> {
454        DeclarationImportanceIterator::new(&self.declarations, &self.declarations_importance)
455    }
456
457    /// Iterate over `PropertyDeclaration` for Importance::Normal
458    #[inline]
459    pub fn normal_declaration_iter(&self) -> impl DoubleEndedIterator<Item = &PropertyDeclaration> {
460        self.declaration_importance_iter()
461            .filter(|(_, importance)| !importance.important())
462            .map(|(declaration, _)| declaration)
463    }
464
465    /// Return an iterator of (AnimatableLonghand, AnimationValue).
466    #[inline]
467    pub fn to_animation_value_iter<'a, 'cx, 'cx_a: 'cx>(
468        &'a self,
469        context: &'cx mut Context<'cx_a>,
470        style: &'a ComputedValues,
471        default_values: &'a ComputedValues,
472    ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
473        AnimationValueIterator::new(self, context, style, default_values)
474    }
475
476    /// Returns whether this block contains any declaration with `!important`.
477    ///
478    /// This is based on the `declarations_importance` bit-vector,
479    /// which should be maintained whenever `declarations` is changed.
480    #[inline]
481    pub fn any_important(&self) -> bool {
482        !self.declarations_importance.all_false()
483    }
484
485    /// Returns whether this block contains any declaration without `!important`.
486    ///
487    /// This is based on the `declarations_importance` bit-vector,
488    /// which should be maintained whenever `declarations` is changed.
489    #[inline]
490    pub fn any_normal(&self) -> bool {
491        !self.declarations_importance.all_true()
492    }
493
494    /// Returns a `PropertyDeclarationIdSet` representing the properties that are changed in
495    /// this block.
496    #[inline]
497    pub fn property_ids(&self) -> &PropertyDeclarationIdSet {
498        &self.property_ids
499    }
500
501    /// Returns whether this block contains a declaration of a given property id.
502    #[inline]
503    pub fn contains(&self, id: PropertyDeclarationId) -> bool {
504        self.property_ids.contains(id)
505    }
506
507    /// Returns whether this block contains any reset longhand.
508    #[inline]
509    pub fn contains_any_reset(&self) -> bool {
510        self.property_ids.contains_any_reset()
511    }
512
513    /// Get a declaration for a given property.
514    ///
515    /// NOTE: This is linear time in the case of custom properties or in the
516    /// case the longhand is actually in the declaration block.
517    #[inline]
518    pub fn get(
519        &self,
520        property: PropertyDeclarationId,
521    ) -> Option<(&PropertyDeclaration, Importance)> {
522        if !self.contains(property) {
523            return None;
524        }
525        self.declaration_importance_iter()
526            .find(|(declaration, _)| declaration.id() == property)
527    }
528
529    /// Tries to serialize a given shorthand from the declarations in this
530    /// block.
531    pub fn shorthand_to_css(
532        &self,
533        shorthand: ShorthandId,
534        dest: &mut CssStringWriter,
535    ) -> fmt::Result {
536        // Step 1.2.1 of
537        // https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue
538        let mut list = SmallVec::<[&_; 10]>::new();
539        let mut important_count = 0;
540
541        // Step 1.2.2
542        for longhand in shorthand.longhands() {
543            // Step 1.2.2.1
544            let declaration = self.get(PropertyDeclarationId::Longhand(longhand));
545
546            // Step 1.2.2.2 & 1.2.2.3
547            match declaration {
548                Some((declaration, importance)) => {
549                    list.push(declaration);
550                    if importance.important() {
551                        important_count += 1;
552                    }
553                },
554                None => return Ok(()),
555            }
556        }
557
558        // If there is one or more longhand with important, and one or more
559        // without important, we don't serialize it as a shorthand.
560        if important_count > 0 && important_count != list.len() {
561            return Ok(());
562        }
563
564        // Step 1.2.3
565        // We don't print !important when serializing individual properties,
566        // so we treat this as a normal-importance property
567        match shorthand.get_shorthand_appendable_value(&list) {
568            Some(appendable_value) => append_declaration_value(dest, appendable_value),
569            None => Ok(()),
570        }
571    }
572
573    /// Find the value of the given property in this block and serialize it
574    ///
575    /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue>
576    pub fn property_value_to_css(
577        &self,
578        property: &PropertyId,
579        dest: &mut CssStringWriter,
580    ) -> fmt::Result {
581        // Step 1.1: done when parsing a string to PropertyId
582
583        // Step 1.2
584        let longhand_or_custom = match property.as_shorthand() {
585            Ok(shorthand) => return self.shorthand_to_css(shorthand, dest),
586            Err(longhand_or_custom) => longhand_or_custom,
587        };
588
589        if let Some((value, _importance)) = self.get(longhand_or_custom) {
590            // Step 2
591            value.to_css(dest)
592        } else {
593            // Step 3
594            Ok(())
595        }
596    }
597
598    /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertypriority>
599    pub fn property_priority(&self, property: &PropertyId) -> Importance {
600        // Step 1: done when parsing a string to PropertyId
601
602        // Step 2
603        match property.as_shorthand() {
604            Ok(shorthand) => {
605                // Step 2.1 & 2.2 & 2.3
606                if shorthand.longhands().all(|l| {
607                    self.get(PropertyDeclarationId::Longhand(l))
608                        .is_some_and(|(_, importance)| importance.important())
609                }) {
610                    Importance::Important
611                } else {
612                    Importance::Normal
613                }
614            },
615            Err(longhand_or_custom) => {
616                // Step 3
617                self.get(longhand_or_custom)
618                    .map_or(Importance::Normal, |(_, importance)| importance)
619            },
620        }
621    }
622
623    /// Find the value of the given property in this block and reify it.
624    /// Returns `Err(())` if the property is not present in this declaration
625    /// block.
626    pub fn property_value_to_typed_value_list(
627        &self,
628        property: &PropertyId,
629    ) -> Result<Option<TypedValueList>, ()> {
630        match property.as_shorthand() {
631            Ok(shorthand) => {
632                if shorthand
633                    .longhands()
634                    .all(|longhand| self.contains(PropertyDeclarationId::Longhand(longhand)))
635                {
636                    Ok(None)
637                } else {
638                    Err(())
639                }
640            },
641            Err(longhand_or_custom) => match self.get(longhand_or_custom) {
642                Some((value, _importance)) => Ok(value.to_typed_value_list()),
643                None => Err(()),
644            },
645        }
646    }
647
648    /// Adds or overrides the declaration for a given property in this block.
649    ///
650    /// See the documentation of `push` to see what impact `source` has when the
651    /// property is already there.
652    pub fn extend(
653        &mut self,
654        mut drain: SourcePropertyDeclarationDrain,
655        importance: Importance,
656    ) -> bool {
657        let all_shorthand_len = match drain.all_shorthand {
658            AllShorthand::NotSet => 0,
659            AllShorthand::CSSWideKeyword(_) | AllShorthand::WithVariables(_) => {
660                property_counts::ALL_SHORTHAND_EXPANDED
661            },
662        };
663        let push_calls_count = drain.declarations.len() + all_shorthand_len;
664
665        // With deduplication the actual length increase may be less than this.
666        self.declarations.reserve(push_calls_count);
667
668        let mut changed = false;
669        for decl in &mut drain.declarations {
670            changed |= self.push(decl, importance);
671        }
672        drain
673            .all_shorthand
674            .declarations()
675            .fold(changed, |changed, decl| {
676                changed | self.push(decl, importance)
677            })
678    }
679
680    /// Adds or overrides the declaration for a given property in this block.
681    ///
682    /// Returns whether the declaration has changed.
683    ///
684    /// This is only used for parsing and internal use.
685    pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) -> bool {
686        let id = declaration.id();
687        if !self.property_ids.insert(id) {
688            let mut index_to_remove = None;
689            for (i, slot) in self.declarations.iter_mut().enumerate() {
690                if slot.id() != id {
691                    continue;
692                }
693
694                let important = self.declarations_importance[i];
695
696                // For declarations from parsing, non-important declarations
697                // shouldn't override existing important one.
698                if important && !importance.important() {
699                    return false;
700                }
701
702                index_to_remove = Some(i);
703                break;
704            }
705
706            if let Some(index) = index_to_remove {
707                self.declarations.remove(index);
708                self.declarations_importance.remove(index);
709                self.declarations.push(declaration);
710                self.declarations_importance.push(importance.important());
711                return true;
712            }
713        }
714
715        self.declarations.push(declaration);
716        self.declarations_importance.push(importance.important());
717        true
718    }
719
720    /// Prepares updating this declaration block with the given
721    /// `SourcePropertyDeclaration` and importance, and returns whether
722    /// there is something to update.
723    pub fn prepare_for_update(
724        &self,
725        source_declarations: &SourcePropertyDeclaration,
726        importance: Importance,
727        updates: &mut SourcePropertyDeclarationUpdate,
728    ) -> bool {
729        debug_assert!(updates.updates.is_empty());
730        // Check whether we are updating for an all shorthand change.
731        if !matches!(source_declarations.all_shorthand, AllShorthand::NotSet) {
732            debug_assert!(source_declarations.declarations.is_empty());
733            return source_declarations
734                .all_shorthand
735                .declarations()
736                .any(|decl| {
737                    !self.contains(decl.id())
738                        || self
739                            .declarations
740                            .iter()
741                            .enumerate()
742                            .find(|&(_, d)| d.id() == decl.id())
743                            .is_none_or(|(i, d)| {
744                                let important = self.declarations_importance[i];
745                                *d != decl || important != importance.important()
746                            })
747                });
748        }
749        // Fill `updates` with update information.
750        let mut any_update = false;
751        let new_count = &mut updates.new_count;
752        let any_removal = &mut updates.any_removal;
753        let updates = &mut updates.updates;
754        updates.extend(
755            source_declarations
756                .declarations
757                .iter()
758                .map(|declaration| {
759                    if !self.contains(declaration.id()) {
760                        return DeclarationUpdate::Append;
761                    }
762                    let longhand_id = declaration.id().as_longhand();
763                    if let Some(longhand_id) = longhand_id
764                        && let Some(logical_group) = longhand_id.logical_group()
765                    {
766                        let mut needs_append = false;
767                        for (pos, decl) in self.declarations.iter().enumerate().rev() {
768                            let id = match decl.id().as_longhand() {
769                                Some(id) => id,
770                                None => continue,
771                            };
772                            if id == longhand_id {
773                                if needs_append {
774                                    return DeclarationUpdate::AppendAndRemove { pos };
775                                }
776                                let important = self.declarations_importance[pos];
777                                if decl == declaration && important == importance.important() {
778                                    return DeclarationUpdate::None;
779                                }
780                                return DeclarationUpdate::UpdateInPlace { pos };
781                            }
782                            if !needs_append
783                                && id.logical_group() == Some(logical_group)
784                                && id.is_logical() != longhand_id.is_logical()
785                            {
786                                needs_append = true;
787                            }
788                        }
789                        unreachable!("Longhand should be found in loop above");
790                    }
791                    self.declarations
792                        .iter()
793                        .enumerate()
794                        .find(|&(_, decl)| decl.id() == declaration.id())
795                        .map_or(DeclarationUpdate::Append, |(pos, decl)| {
796                            let important = self.declarations_importance[pos];
797                            if decl == declaration && important == importance.important() {
798                                DeclarationUpdate::None
799                            } else {
800                                DeclarationUpdate::UpdateInPlace { pos }
801                            }
802                        })
803                })
804                .inspect(|update| {
805                    if matches!(update, DeclarationUpdate::None) {
806                        return;
807                    }
808                    any_update = true;
809                    match update {
810                        DeclarationUpdate::Append => {
811                            *new_count += 1;
812                        },
813                        DeclarationUpdate::AppendAndRemove { .. } => {
814                            *any_removal = true;
815                        },
816                        _ => {},
817                    }
818                }),
819        );
820        any_update
821    }
822
823    /// Update this declaration block with the given data.
824    pub fn update(
825        &mut self,
826        drain: SourcePropertyDeclarationDrain,
827        importance: Importance,
828        updates: &mut SourcePropertyDeclarationUpdate,
829    ) {
830        let important = importance.important();
831        if !matches!(drain.all_shorthand, AllShorthand::NotSet) {
832            debug_assert!(updates.updates.is_empty());
833            for decl in drain.all_shorthand.declarations() {
834                let id = decl.id();
835                if self.property_ids.insert(id) {
836                    self.declarations.push(decl);
837                    self.declarations_importance.push(important);
838                } else {
839                    let (idx, slot) = self
840                        .declarations
841                        .iter_mut()
842                        .enumerate()
843                        .find(|(_, d)| d.id() == decl.id())
844                        .unwrap();
845                    *slot = decl;
846                    self.declarations_importance.set(idx, important);
847                }
848            }
849            return;
850        }
851
852        self.declarations.reserve(updates.new_count);
853        if updates.any_removal {
854            // Prepare for removal and fixing update positions.
855            struct UpdateOrRemoval<'a> {
856                item: &'a mut DeclarationUpdate,
857                pos: usize,
858                remove: bool,
859            }
860            let mut updates_and_removals: SubpropertiesVec<UpdateOrRemoval> = updates
861                .updates
862                .iter_mut()
863                .filter_map(|item| {
864                    let (pos, remove) = match *item {
865                        DeclarationUpdate::UpdateInPlace { pos } => (pos, false),
866                        DeclarationUpdate::AppendAndRemove { pos } => (pos, true),
867                        _ => return None,
868                    };
869                    Some(UpdateOrRemoval { item, pos, remove })
870                })
871                .collect();
872            // Execute removals. It's important to do it in reverse index order,
873            // so that removing doesn't invalidate following positions.
874            updates_and_removals.sort_unstable_by_key(|update| update.pos);
875            updates_and_removals
876                .iter()
877                .rev()
878                .filter(|update| update.remove)
879                .for_each(|update| {
880                    self.declarations.remove(update.pos);
881                    self.declarations_importance.remove(update.pos);
882                });
883            // Fixup pos field for updates.
884            let mut removed_count = 0;
885            for update in updates_and_removals.iter_mut() {
886                if update.remove {
887                    removed_count += 1;
888                    continue;
889                }
890                debug_assert_eq!(
891                    *update.item,
892                    DeclarationUpdate::UpdateInPlace { pos: update.pos }
893                );
894                *update.item = DeclarationUpdate::UpdateInPlace {
895                    pos: update.pos - removed_count,
896                };
897            }
898        }
899        // Execute updates and appends.
900        for (decl, update) in drain.declarations.zip_eq(updates.updates.iter()) {
901            match *update {
902                DeclarationUpdate::None => {},
903                DeclarationUpdate::Append | DeclarationUpdate::AppendAndRemove { .. } => {
904                    self.property_ids.insert(decl.id());
905                    self.declarations.push(decl);
906                    self.declarations_importance.push(important);
907                },
908                DeclarationUpdate::UpdateInPlace { pos } => {
909                    self.declarations[pos] = decl;
910                    self.declarations_importance.set(pos, important);
911                },
912            }
913        }
914        updates.updates.clear();
915    }
916
917    /// Returns the first declaration that would be removed by removing
918    /// `property`.
919    #[inline]
920    pub fn first_declaration_to_remove(&self, property: &PropertyId) -> Option<usize> {
921        if let Err(longhand_or_custom) = property.as_shorthand()
922            && !self.contains(longhand_or_custom)
923        {
924            return None;
925        }
926
927        self.declarations
928            .iter()
929            .position(|declaration| declaration.id().is_or_is_longhand_of(property))
930    }
931
932    /// Removes a given declaration at a given index.
933    #[inline]
934    fn remove_declaration_at(&mut self, i: usize) {
935        self.property_ids.remove(self.declarations[i].id());
936        self.declarations_importance.remove(i);
937        self.declarations.remove(i);
938    }
939
940    /// Clears all the declarations from this block.
941    #[inline]
942    pub fn clear(&mut self) {
943        self.declarations_importance.clear();
944        self.declarations.clear();
945        self.property_ids.clear();
946    }
947
948    /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-removeproperty>
949    ///
950    /// `first_declaration` needs to be the result of
951    /// `first_declaration_to_remove`.
952    #[inline]
953    pub fn remove_property(&mut self, property: &PropertyId, first_declaration: usize) {
954        debug_assert_eq!(
955            Some(first_declaration),
956            self.first_declaration_to_remove(property)
957        );
958        debug_assert!(
959            self.declarations[first_declaration]
960                .id()
961                .is_or_is_longhand_of(property)
962        );
963
964        self.remove_declaration_at(first_declaration);
965
966        let shorthand = match property.as_shorthand() {
967            Ok(s) => s,
968            Err(_longhand_or_custom) => return,
969        };
970
971        let mut i = first_declaration;
972        let mut len = self.len();
973        while i < len {
974            if !self.declarations[i].id().is_longhand_of(shorthand) {
975                i += 1;
976                continue;
977            }
978
979            self.remove_declaration_at(i);
980            len -= 1;
981        }
982    }
983
984    /// Take a declaration block known to contain a single property and serialize it.
985    pub fn single_value_to_css(
986        &self,
987        property: &PropertyId,
988        dest: &mut CssStringWriter,
989        computed_values: Option<&ComputedValues>,
990        stylist: &Stylist,
991    ) -> fmt::Result {
992        if let Ok(shorthand) = property.as_shorthand() {
993            return self.shorthand_to_css(shorthand, dest);
994        }
995
996        // FIXME(emilio): Should this assert, or assert that the declaration is
997        // the property we expect?
998        let declaration = match self.declarations.first() {
999            Some(d) => d,
1000            None => return Err(fmt::Error),
1001        };
1002
1003        let mut rule_cache_conditions = RuleCacheConditions::default();
1004        let mut tree_counting_caches = TreeCountingCaches::default();
1005        let mut context = Context::new(
1006            StyleBuilder::new(
1007                stylist.device(),
1008                Some(stylist),
1009                computed_values,
1010                None,
1011                None,
1012                false,
1013            ),
1014            stylist.quirks_mode(),
1015            &mut rule_cache_conditions,
1016            ContainerSizeQuery::none(),
1017            RuleCascadeFlags::empty(),
1018            &DummyElementContext {},
1019            &mut tree_counting_caches,
1020        );
1021
1022        if let Some(cv) = computed_values {
1023            context.builder.substitution_functions.custom_properties =
1024                cv.custom_properties().clone();
1025        };
1026
1027        match (declaration, computed_values) {
1028            // If we have a longhand declaration with variables, those variables
1029            // will be stored as unparsed values.
1030            //
1031            // As a temporary measure to produce sensible results in Gecko's
1032            // getKeyframes() implementation for CSS animations, if
1033            // |computed_values| is supplied, we use it to expand such variable
1034            // declarations. This will be fixed properly in Gecko bug 1391537.
1035            (PropertyDeclaration::WithVariables(declaration), Some(_)) => declaration
1036                .value
1037                .substitute_variables(
1038                    declaration.id,
1039                    &context.builder.substitution_functions,
1040                    stylist,
1041                    &context,
1042                    &mut Default::default(),
1043                    &mut AttributeTracker::new_dummy(),
1044                )
1045                .to_css(dest),
1046            (d, _) => d.to_css(dest),
1047        }
1048    }
1049
1050    /// Convert AnimationValueMap to PropertyDeclarationBlock.
1051    pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self {
1052        let len = animation_value_map.len();
1053        let mut declarations = ThinVec::with_capacity(len);
1054        let mut property_ids = PropertyDeclarationIdSet::default();
1055
1056        for (property, animation_value) in animation_value_map.iter() {
1057            property_ids.insert(property.as_borrowed());
1058            declarations.push(animation_value.uncompute());
1059        }
1060
1061        PropertyDeclarationBlock {
1062            declarations,
1063            property_ids,
1064            declarations_importance: SmallBitVec::from_elem(len, false),
1065            immutable: AtomicBool::new(false),
1066        }
1067    }
1068
1069    /// Returns true if the declaration block has a CSSWideKeyword for the given
1070    /// property.
1071    pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
1072        if let Err(longhand_or_custom) = property.as_shorthand()
1073            && !self.property_ids.contains(longhand_or_custom)
1074        {
1075            return false;
1076        }
1077        self.declarations.iter().any(|decl| {
1078            decl.id().is_or_is_longhand_of(property) && decl.get_css_wide_keyword().is_some()
1079        })
1080    }
1081
1082    /// Like the method on ToCss, but without the type parameter to avoid
1083    /// accidentally monomorphizing this large function multiple times for
1084    /// different writers.
1085    ///
1086    /// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
1087    pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
1088        let mut is_first_serialization = true; // trailing serializations should have a prepended space
1089
1090        // Step 1 -> dest = result list
1091
1092        // Step 2
1093        //
1094        // NOTE(emilio): We reuse this set for both longhands and shorthands
1095        // with subtly different meaning. For longhands, only longhands that
1096        // have actually been serialized (either by themselves, or as part of a
1097        // shorthand) appear here. For shorthands, all the shorthands that we've
1098        // attempted to serialize appear here.
1099        let mut already_serialized = NonCustomPropertyIdSet::new();
1100
1101        // Step 3
1102        'declaration_loop: for (declaration, importance) in self.declaration_importance_iter() {
1103            // Step 3.1
1104            let property = declaration.id();
1105            let longhand_id = match property {
1106                PropertyDeclarationId::Longhand(id) => id,
1107                PropertyDeclarationId::Custom(..) => {
1108                    // Given the invariants that there are no duplicate
1109                    // properties in a declaration block, and that custom
1110                    // properties can't be part of a shorthand, we can just care
1111                    // about them here.
1112                    append_serialization(
1113                        dest,
1114                        &property,
1115                        AppendableValue::Declaration(declaration),
1116                        importance,
1117                        &mut is_first_serialization,
1118                    )?;
1119                    continue;
1120                },
1121            };
1122
1123            // Step 3.2
1124            if already_serialized.contains(longhand_id.into()) {
1125                continue;
1126            }
1127
1128            // Steps 3.3 & 3.4
1129            for shorthand in longhand_id.shorthands() {
1130                // We already attempted to serialize this shorthand before.
1131                if already_serialized.contains(shorthand.into()) {
1132                    continue;
1133                }
1134                already_serialized.insert(shorthand.into());
1135
1136                if shorthand.is_legacy_shorthand()
1137                    && !(shorthand.allows_disabled_subproperties()
1138                        && !NonCustomPropertyId::from(longhand_id).enabled_for_all_content())
1139                {
1140                    // TODO(Bug 1540681): Remove when shipping line-clamp.
1141                    continue;
1142                }
1143
1144                // Step 3.3.1:
1145                //     Let longhands be an array consisting of all CSS
1146                //     declarations in declaration block’s declarations that
1147                //     that are not in already serialized and have a property
1148                //     name that maps to one of the shorthand properties in
1149                //     shorthands.
1150                let longhands = {
1151                    // TODO(emilio): This could just index in an array if we
1152                    // remove pref-controlled longhands.
1153                    let mut ids = LonghandIdSet::new();
1154                    for longhand in shorthand.longhands() {
1155                        ids.insert(longhand);
1156                    }
1157                    ids
1158                };
1159
1160                // Step 3.4.2
1161                //     If all properties that map to shorthand are not present
1162                //     in longhands, continue with the steps labeled shorthand
1163                //     loop.
1164                if !self.property_ids.contains_all_longhands(&longhands) {
1165                    continue;
1166                }
1167
1168                // Step 3.4.3:
1169                //     Let current longhands be an empty array.
1170                let mut current_longhands = SmallVec::<[&_; 10]>::new();
1171                let mut logical_groups = LogicalGroupSet::new();
1172                let mut saw_one = false;
1173                let mut logical_mismatch = false;
1174                let mut seen = LonghandIdSet::new();
1175                let mut important_count = 0;
1176
1177                // Step 3.4.4:
1178                //    Append all CSS declarations in longhands that have a
1179                //    property name that maps to shorthand to current longhands.
1180                for (declaration, importance) in self.declaration_importance_iter() {
1181                    let longhand = match declaration.id() {
1182                        PropertyDeclarationId::Longhand(id) => id,
1183                        PropertyDeclarationId::Custom(..) => continue,
1184                    };
1185
1186                    if longhands.contains(longhand) {
1187                        saw_one = true;
1188                        if importance.important() {
1189                            important_count += 1;
1190                        }
1191                        current_longhands.push(declaration);
1192                        if shorthand != ShorthandId::All {
1193                            // All is special because it contains both physical
1194                            // and logical longhands.
1195                            if let Some(g) = longhand.logical_group() {
1196                                logical_groups.insert(g);
1197                            }
1198                            seen.insert(longhand);
1199                            if seen == longhands {
1200                                break;
1201                            }
1202                        }
1203                    } else if saw_one
1204                        && let Some(g) = longhand.logical_group()
1205                        && logical_groups.contains(g)
1206                    {
1207                        logical_mismatch = true;
1208                        break;
1209                    }
1210                }
1211
1212                // 3.4.5:
1213                //     If there is one or more CSS declarations in current
1214                //     longhands have their important flag set and one or more
1215                //     with it unset, continue with the steps labeled shorthand
1216                //     loop.
1217                let is_important = important_count > 0;
1218                if is_important && important_count != current_longhands.len() {
1219                    continue;
1220                }
1221
1222                // 3.4.6:
1223                //    If there’s any declaration in declaration block in between
1224                //    the first and the last longhand in current longhands which
1225                //    belongs to the same logical property group, but has a
1226                //    different mapping logic as any of the longhands in current
1227                //    longhands, and is not in current longhands, continue with
1228                //    the steps labeled shorthand loop.
1229                if logical_mismatch {
1230                    continue;
1231                }
1232
1233                let importance = if is_important {
1234                    Importance::Important
1235                } else {
1236                    Importance::Normal
1237                };
1238
1239                // 3.4.7:
1240                //    Let value be the result of invoking serialize a CSS value
1241                //    of current longhands.
1242                let appendable_value =
1243                    match shorthand.get_shorthand_appendable_value(&current_longhands) {
1244                        None => continue,
1245                        Some(appendable_value) => appendable_value,
1246                    };
1247
1248                // We avoid re-serializing if we're already an
1249                // AppendableValue::Css.
1250                let mut v = CssString::new();
1251                let value = match appendable_value {
1252                    AppendableValue::Css(css) => {
1253                        debug_assert!(!css.is_empty());
1254                        appendable_value
1255                    },
1256                    other => {
1257                        append_declaration_value(&mut v, other)?;
1258
1259                        // 3.4.8:
1260                        //     If value is the empty string, continue with the
1261                        //     steps labeled shorthand loop.
1262                        if v.is_empty() {
1263                            continue;
1264                        }
1265
1266                        AppendableValue::Css({
1267                            // Safety: serialization only generates valid utf-8.
1268                            #[cfg(feature = "gecko")]
1269                            unsafe {
1270                                v.as_str_unchecked()
1271                            }
1272                            #[cfg(feature = "servo")]
1273                            &v
1274                        })
1275                    },
1276                };
1277
1278                // 3.4.9:
1279                //     Let serialized declaration be the result of invoking
1280                //     serialize a CSS declaration with property name shorthand,
1281                //     value value, and the important flag set if the CSS
1282                //     declarations in current longhands have their important
1283                //     flag set.
1284                //
1285                // 3.4.10:
1286                //     Append serialized declaration to list.
1287                append_serialization(
1288                    dest,
1289                    &shorthand,
1290                    value,
1291                    importance,
1292                    &mut is_first_serialization,
1293                )?;
1294
1295                // 3.4.11:
1296                //     Append the property names of all items of current
1297                //     longhands to already serialized.
1298                for current_longhand in &current_longhands {
1299                    let longhand_id = match current_longhand.id() {
1300                        PropertyDeclarationId::Longhand(id) => id,
1301                        PropertyDeclarationId::Custom(..) => unreachable!(),
1302                    };
1303
1304                    // Substep 9
1305                    already_serialized.insert(longhand_id.into());
1306                }
1307
1308                // 3.4.12:
1309                //     Continue with the steps labeled declaration loop.
1310                continue 'declaration_loop;
1311            }
1312
1313            // Steps 3.5, 3.6 & 3.7:
1314            //     Let value be the result of invoking serialize a CSS value of
1315            //     declaration.
1316            //
1317            //     Let serialized declaration be the result of invoking
1318            //     serialize a CSS declaration with property name property,
1319            //     value value, and the important flag set if declaration has
1320            //     its important flag set.
1321            //
1322            //     Append serialized declaration to list.
1323            append_serialization(
1324                dest,
1325                &property,
1326                AppendableValue::Declaration(declaration),
1327                importance,
1328                &mut is_first_serialization,
1329            )?;
1330
1331            // Step 3.8:
1332            //     Append property to already serialized.
1333            already_serialized.insert(longhand_id.into());
1334        }
1335
1336        // Step 4
1337        Ok(())
1338    }
1339}
1340
1341/// A convenient enum to represent different kinds of stuff that can represent a
1342/// _value_ in the serialization of a property declaration.
1343pub enum AppendableValue<'a, 'b: 'a> {
1344    /// A given declaration, of which we'll serialize just the value.
1345    Declaration(&'a PropertyDeclaration),
1346    /// A set of declarations for a given shorthand.
1347    ///
1348    /// FIXME: This needs more docs, where are the shorthands expanded? We print
1349    /// the property name before-hand, don't we?
1350    DeclarationsForShorthand(ShorthandId, &'a [&'b PropertyDeclaration]),
1351    /// A raw CSS string, coming for example from a property with CSS variables,
1352    /// or when storing a serialized shorthand value before appending directly.
1353    Css(&'a str),
1354}
1355
1356/// Potentially appends whitespace after the first (property: value;) pair.
1357fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result
1358where
1359    W: Write,
1360{
1361    if !*is_first_serialization {
1362        dest.write_char(' ')
1363    } else {
1364        *is_first_serialization = false;
1365        Ok(())
1366    }
1367}
1368
1369/// Append a given kind of appendable value to a serialization.
1370pub fn append_declaration_value<'a, 'b: 'a>(
1371    dest: &mut CssStringWriter,
1372    appendable_value: AppendableValue<'a, 'b>,
1373) -> fmt::Result {
1374    match appendable_value {
1375        AppendableValue::Css(css) => dest.write_str(css),
1376        AppendableValue::Declaration(decl) => decl.to_css(dest),
1377        AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
1378            shorthand.longhands_to_css(decls, dest)
1379        },
1380    }
1381}
1382
1383/// Append a given property and value pair to a serialization.
1384pub fn append_serialization<'a, 'b: 'a, N>(
1385    dest: &mut CssStringWriter,
1386    property_name: &N,
1387    appendable_value: AppendableValue<'a, 'b>,
1388    importance: Importance,
1389    is_first_serialization: &mut bool,
1390) -> fmt::Result
1391where
1392    N: ToCss,
1393{
1394    handle_first_serialization(dest, is_first_serialization)?;
1395
1396    property_name.to_css(&mut CssWriter::new(dest))?;
1397    dest.write_str(": ")?;
1398
1399    append_declaration_value(dest, appendable_value)?;
1400
1401    if importance.important() {
1402        dest.write_str(" !important")?;
1403    }
1404
1405    dest.write_char(';')
1406}
1407
1408/// A helper to parse the style attribute of an element, in order for this to be
1409/// shared between Servo and Gecko.
1410///
1411/// Inline because we call this cross-crate.
1412#[inline]
1413pub fn parse_style_attribute(
1414    input: &str,
1415    url_data: &UrlExtraData,
1416    error_reporter: Option<&dyn ParseErrorReporter>,
1417    quirks_mode: QuirksMode,
1418    rule_type: CssRuleType,
1419) -> PropertyDeclarationBlock {
1420    let mut context = ParserContext::new(
1421        Origin::Author,
1422        url_data,
1423        Some(rule_type),
1424        ParsingMode::DEFAULT,
1425        quirks_mode,
1426        /* namespaces = */ Default::default(),
1427        error_reporter,
1428        None,
1429        /* attr_taint */ Default::default(),
1430    );
1431
1432    parse_property_declaration_list(&mut context, &mut Parser::new(input), &[])
1433}
1434
1435/// Parse a given property declaration. Can result in multiple
1436/// `PropertyDeclaration`s when expanding a shorthand, for example.
1437///
1438/// This does not attempt to parse !important at all.
1439#[inline]
1440pub fn parse_one_declaration_into(
1441    declarations: &mut SourcePropertyDeclaration,
1442    id: PropertyId,
1443    input: &str,
1444    origin: Origin,
1445    url_data: &UrlExtraData,
1446    error_reporter: Option<&dyn ParseErrorReporter>,
1447    parsing_mode: ParsingMode,
1448    quirks_mode: QuirksMode,
1449    rule_type: CssRuleType,
1450) -> Result<(), ()> {
1451    let mut context = ParserContext::new(
1452        origin,
1453        url_data,
1454        Some(rule_type),
1455        parsing_mode,
1456        quirks_mode,
1457        /* namespaces = */ Default::default(),
1458        error_reporter,
1459        None,
1460        /* attr_taint */ Default::default(),
1461    );
1462
1463    let property_id_for_error_reporting = if context.error_reporting_enabled() {
1464        Some(id.clone())
1465    } else {
1466        None
1467    };
1468
1469    let mut parser = Parser::new(input);
1470    let start_position = parser.position();
1471    let start_location = parser.current_source_location();
1472    parser
1473        .parse_entirely(|parser| {
1474            PropertyDeclaration::parse_into(declarations, id, &mut context, parser)
1475        })
1476        .map_err(|err| {
1477            if context.error_reporting_enabled() {
1478                report_one_css_error(
1479                    &context,
1480                    None,
1481                    &[],
1482                    err,
1483                    parser.slice_from(start_position),
1484                    start_location,
1485                    property_id_for_error_reporting,
1486                )
1487            }
1488        })
1489}
1490
1491/// A struct to parse property declarations.
1492struct PropertyDeclarationParser<'a, 'b: 'a, 'i> {
1493    context: &'a mut ParserContext<'b>,
1494    state: &'a mut DeclarationParserState<'i>,
1495}
1496
1497/// The state needed to parse a declaration block.
1498///
1499/// It stores declarations in output_block.
1500#[derive(Default)]
1501pub struct DeclarationParserState<'i> {
1502    /// The output block where results are stored.
1503    output_block: PropertyDeclarationBlock,
1504    /// Declarations from the last declaration parsed. (note that a shorthand might expand to
1505    /// multiple declarations).
1506    declarations: SourcePropertyDeclaration,
1507    /// The importance from the last declaration parsed.
1508    importance: Importance,
1509    /// A list of errors that have happened so far. Not all of them might be reported.
1510    errors: SmallParseErrorVec<'i>,
1511    /// The start of the first declaration
1512    first_declaration_start: SourceLocation,
1513    /// The last parsed property id, if any.
1514    last_parsed_property_id: Option<PropertyId>,
1515}
1516
1517impl<'i> DeclarationParserState<'i> {
1518    /// Getter for first_declaration_start.
1519    pub fn first_declaration_start(&self) -> SourceLocation {
1520        self.first_declaration_start
1521    }
1522
1523    /// Returns whether any parsed declarations have been parsed so far.
1524    pub fn has_parsed_declarations(&self) -> bool {
1525        !self.output_block.is_empty()
1526    }
1527
1528    /// Takes the parsed declarations.
1529    pub fn take_declarations(&mut self) -> PropertyDeclarationBlock {
1530        std::mem::take(&mut self.output_block)
1531    }
1532
1533    /// Parse a single declaration value.
1534    pub fn parse_value(
1535        &mut self,
1536        context: &mut ParserContext,
1537        name: CowRcStr<'i>,
1538        input: &mut Parser<'i>,
1539        declaration_start: &ParserState,
1540    ) -> Result<(), ParseError> {
1541        let id = match PropertyId::parse(&name, context) {
1542            Ok(id) => id,
1543            Err(..) => {
1544                return Err(ParseError::custom(StyleParseErrorKind::UnknownProperty));
1545            },
1546        };
1547        if context.error_reporting_enabled() {
1548            self.last_parsed_property_id = Some(id.clone());
1549        }
1550        input.parse_until_before(Delimiter::Bang, |input| {
1551            PropertyDeclaration::parse_into(&mut self.declarations, id, context, input)
1552        })?;
1553        self.importance = match input.try_parse(parse_important) {
1554            Ok(()) => {
1555                if !context.allows_important_declarations() {
1556                    return Err(ParseError::custom(
1557                        StyleParseErrorKind::UnexpectedImportantDeclaration,
1558                    ));
1559                }
1560                Importance::Important
1561            },
1562            Err(_) => Importance::Normal,
1563        };
1564        // In case there is still unparsed text in the declaration, we should roll back.
1565        input.expect_exhausted()?;
1566        let has_parsed_declarations = self.has_parsed_declarations();
1567        self.output_block
1568            .extend(self.declarations.drain(), self.importance);
1569        // We've successfully parsed a declaration, so forget about
1570        // `last_parsed_property_id`. It'd be wrong to associate any
1571        // following error with this property.
1572        self.last_parsed_property_id = None;
1573
1574        if !has_parsed_declarations {
1575            self.first_declaration_start = declaration_start.source_location();
1576        }
1577
1578        Ok(())
1579    }
1580
1581    /// Reports any CSS errors that have ocurred if needed.
1582    #[inline]
1583    pub fn report_errors_if_needed(
1584        &mut self,
1585        context: &ParserContext,
1586        selectors: &[SelectorList<SelectorImpl>],
1587    ) {
1588        if self.errors.is_empty() {
1589            return;
1590        }
1591        self.do_report_css_errors(context, selectors);
1592    }
1593
1594    #[cold]
1595    fn do_report_css_errors(
1596        &mut self,
1597        context: &ParserContext,
1598        selectors: &[SelectorList<SelectorImpl>],
1599    ) {
1600        for (error, slice, location, property) in self.errors.drain(..) {
1601            report_one_css_error(
1602                context,
1603                Some(&self.output_block),
1604                selectors,
1605                error,
1606                slice,
1607                location,
1608                property,
1609            )
1610        }
1611    }
1612
1613    /// Resets the declaration parser state, and reports the error if needed.
1614    #[inline]
1615    pub fn did_error(
1616        &mut self,
1617        context: &ParserContext,
1618        error: ParseError,
1619        slice: &'i str,
1620        location: SourceLocation,
1621    ) {
1622        self.declarations.clear();
1623        if !context.error_reporting_enabled() {
1624            return;
1625        }
1626        let property = self.last_parsed_property_id.take();
1627        self.errors.push((error, slice, location, property));
1628    }
1629}
1630
1631/// Default methods reject all at rules.
1632impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1633    type Prelude = ();
1634    type AtRule = ();
1635    type Error = StyleParseErrorKind;
1636}
1637
1638/// Default methods reject all rules.
1639impl<'a, 'b, 'i> QualifiedRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1640    type Prelude = ();
1641    type QualifiedRule = ();
1642    type Error = StyleParseErrorKind;
1643}
1644
1645/// Based on NonMozillaVendorIdentifier from Gecko's CSS parser.
1646fn is_non_mozilla_vendor_identifier(name: &str) -> bool {
1647    (name.starts_with("-") && !name.starts_with("-moz-")) || name.starts_with("_")
1648}
1649
1650impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1651    type Declaration = ();
1652    type Error = StyleParseErrorKind;
1653
1654    fn parse_value(
1655        &mut self,
1656        name: CowRcStr<'i>,
1657        input: &mut Parser<'i>,
1658        declaration_start: &ParserState,
1659    ) -> Result<(), ParseError> {
1660        self.state
1661            .parse_value(self.context, name, input, declaration_start)
1662    }
1663}
1664
1665impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind>
1666    for PropertyDeclarationParser<'a, 'b, 'i>
1667{
1668    fn parse_declarations(&self) -> bool {
1669        true
1670    }
1671    // TODO(emilio): Nesting.
1672    fn parse_qualified(&self) -> bool {
1673        false
1674    }
1675}
1676
1677type SmallParseErrorVec<'i> =
1678    SmallVec<[(ParseError, &'i str, SourceLocation, Option<PropertyId>); 2]>;
1679
1680fn alias_of_known_property(name: &str) -> Option<PropertyId> {
1681    let mut prefixed = String::with_capacity(name.len() + 5);
1682    prefixed.push_str("-moz-");
1683    prefixed.push_str(name);
1684    PropertyId::parse_enabled_for_all_content(&prefixed).ok()
1685}
1686
1687#[cold]
1688fn report_one_css_error(
1689    context: &ParserContext,
1690    block: Option<&PropertyDeclarationBlock>,
1691    selectors: &[SelectorList<SelectorImpl>],
1692    mut error: ParseError,
1693    slice: &str,
1694    location: SourceLocation,
1695    property: Option<PropertyId>,
1696) {
1697    debug_assert!(context.error_reporting_enabled());
1698
1699    fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool {
1700        match property.as_shorthand() {
1701            Ok(id) => id
1702                .longhands()
1703                .all(|longhand| block.contains(PropertyDeclarationId::Longhand(longhand))),
1704            Err(longhand_or_custom) => block.contains(longhand_or_custom),
1705        }
1706    }
1707
1708    let mut error_string = Cow::Borrowed(slice);
1709    if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty) = error.kind {
1710        // The error no longer carries the property name, but `slice` is the
1711        // declaration text, i.e. `<name>: <value>`.
1712        let name = slice.split(':').next().unwrap_or("").trim();
1713        if is_non_mozilla_vendor_identifier(name) {
1714            // If the unrecognized property looks like a vendor-specific property,
1715            // silently ignore it instead of polluting the error output.
1716            return;
1717        }
1718        if let Some(alias) = alias_of_known_property(name) {
1719            // This is an unknown property, but its -moz-* version is known.
1720            // We don't want to report error if the -moz-* version is already
1721            // specified.
1722            if let Some(block) = block
1723                && all_properties_in_block(block, &alias)
1724            {
1725                return;
1726            }
1727        }
1728        if !name.is_empty() {
1729            // We don't care about the whole declaration, just the property name
1730            error_string = Cow::Borrowed(name);
1731        }
1732    }
1733
1734    if let Some(ref property) = property {
1735        if let Some(block) = block
1736            && all_properties_in_block(block, property)
1737        {
1738            return;
1739        }
1740        // Was able to parse property ID - Either an invalid value, or is constrained
1741        // by the rule block it's in to be invalid. In the former case, we need to unwrap
1742        // the error to be more specific.
1743        if !matches!(
1744            error.kind,
1745            ParseErrorKind::Custom(StyleParseErrorKind::UnexpectedImportantDeclaration)
1746        ) {
1747            error = ParseError::custom(StyleParseErrorKind::OtherInvalidValue);
1748        }
1749        if !slice.contains(':') {
1750            // For CSSOM we only have the value. If there's no `:`, prepend the property name.
1751            error_string = Cow::Owned(format!("{}: {slice}", property.to_css_string()));
1752        }
1753    }
1754
1755    let error =
1756        ContextualParseError::UnsupportedPropertyDeclaration(&error_string, error, selectors);
1757    context.log_css_error(location, error);
1758}
1759
1760/// Parse a list of property declarations and return a property declaration
1761/// block.
1762pub fn parse_property_declaration_list(
1763    context: &mut ParserContext,
1764    input: &mut Parser,
1765    selectors: &[SelectorList<SelectorImpl>],
1766) -> PropertyDeclarationBlock {
1767    let mut state = DeclarationParserState::default();
1768    let mut parser = PropertyDeclarationParser {
1769        context,
1770        state: &mut state,
1771    };
1772    let mut iter = RuleBodyParser::new(input, &mut parser);
1773    while let Some(declaration) = iter.next() {
1774        match declaration {
1775            Ok(()) => {},
1776            Err((error, slice, location)) => {
1777                let parser = &mut *iter.parser;
1778                parser
1779                    .state
1780                    .did_error(parser.context, error, slice, location)
1781            },
1782        }
1783    }
1784    parser
1785        .state
1786        .report_errors_if_needed(parser.context, selectors);
1787    state.output_block
1788}