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    fn has_declaration_matching(
1070        &self,
1071        property: &PropertyId,
1072        matches: impl Fn(&PropertyDeclaration) -> bool,
1073    ) -> bool {
1074        if let Err(longhand_or_custom) = property.as_shorthand()
1075            && !self.property_ids.contains(longhand_or_custom)
1076        {
1077            return false;
1078        }
1079        self.declarations
1080            .iter()
1081            .any(|decl| decl.id().is_or_is_longhand_of(property) && matches(decl))
1082    }
1083
1084    /// Returns true if the declaration block has a CSSWideKeyword for the given
1085    /// property.
1086    pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
1087        self.has_declaration_matching(property, |decl| decl.get_css_wide_keyword().is_some())
1088    }
1089
1090    /// Returns true if the declaration block has a value with `var()`
1091    /// references for the given property.
1092    pub fn has_unparsed_value(&self, property: &PropertyId) -> bool {
1093        self.has_declaration_matching(property, PropertyDeclaration::is_unparsed)
1094    }
1095
1096    /// Like the method on ToCss, but without the type parameter to avoid
1097    /// accidentally monomorphizing this large function multiple times for
1098    /// different writers.
1099    ///
1100    /// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
1101    pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
1102        let mut is_first_serialization = true; // trailing serializations should have a prepended space
1103
1104        // Step 1 -> dest = result list
1105
1106        // Step 2
1107        //
1108        // NOTE(emilio): We reuse this set for both longhands and shorthands
1109        // with subtly different meaning. For longhands, only longhands that
1110        // have actually been serialized (either by themselves, or as part of a
1111        // shorthand) appear here. For shorthands, all the shorthands that we've
1112        // attempted to serialize appear here.
1113        let mut already_serialized = NonCustomPropertyIdSet::new();
1114
1115        // Step 3
1116        'declaration_loop: for (declaration, importance) in self.declaration_importance_iter() {
1117            // Step 3.1
1118            let property = declaration.id();
1119            let longhand_id = match property {
1120                PropertyDeclarationId::Longhand(id) => id,
1121                PropertyDeclarationId::Custom(..) => {
1122                    // Given the invariants that there are no duplicate
1123                    // properties in a declaration block, and that custom
1124                    // properties can't be part of a shorthand, we can just care
1125                    // about them here.
1126                    append_serialization(
1127                        dest,
1128                        &property,
1129                        AppendableValue::Declaration(declaration),
1130                        importance,
1131                        &mut is_first_serialization,
1132                    )?;
1133                    continue;
1134                },
1135            };
1136
1137            // Step 3.2
1138            if already_serialized.contains(longhand_id.into()) {
1139                continue;
1140            }
1141
1142            // Steps 3.3 & 3.4
1143            for shorthand in longhand_id.shorthands() {
1144                // We already attempted to serialize this shorthand before.
1145                if already_serialized.contains(shorthand.into()) {
1146                    continue;
1147                }
1148                already_serialized.insert(shorthand.into());
1149
1150                if shorthand.is_legacy_shorthand()
1151                    && !(shorthand.allows_disabled_subproperties()
1152                        && !NonCustomPropertyId::from(longhand_id).enabled_for_all_content())
1153                {
1154                    // TODO(Bug 1540681): Remove when shipping line-clamp.
1155                    continue;
1156                }
1157
1158                // Step 3.3.1:
1159                //     Let longhands be an array consisting of all CSS
1160                //     declarations in declaration block’s declarations that
1161                //     that are not in already serialized and have a property
1162                //     name that maps to one of the shorthand properties in
1163                //     shorthands.
1164                let longhands = {
1165                    // TODO(emilio): This could just index in an array if we
1166                    // remove pref-controlled longhands.
1167                    let mut ids = LonghandIdSet::new();
1168                    for longhand in shorthand.longhands() {
1169                        ids.insert(longhand);
1170                    }
1171                    ids
1172                };
1173
1174                // Step 3.4.2
1175                //     If all properties that map to shorthand are not present
1176                //     in longhands, continue with the steps labeled shorthand
1177                //     loop.
1178                if !self.property_ids.contains_all_longhands(&longhands) {
1179                    continue;
1180                }
1181
1182                // Step 3.4.3:
1183                //     Let current longhands be an empty array.
1184                let mut current_longhands = SmallVec::<[&_; 10]>::new();
1185                let mut logical_groups = LogicalGroupSet::new();
1186                let mut saw_one = false;
1187                let mut logical_mismatch = false;
1188                let mut seen = LonghandIdSet::new();
1189                let mut important_count = 0;
1190
1191                // Step 3.4.4:
1192                //    Append all CSS declarations in longhands that have a
1193                //    property name that maps to shorthand to current longhands.
1194                for (declaration, importance) in self.declaration_importance_iter() {
1195                    let longhand = match declaration.id() {
1196                        PropertyDeclarationId::Longhand(id) => id,
1197                        PropertyDeclarationId::Custom(..) => continue,
1198                    };
1199
1200                    if longhands.contains(longhand) {
1201                        saw_one = true;
1202                        if importance.important() {
1203                            important_count += 1;
1204                        }
1205                        current_longhands.push(declaration);
1206                        if shorthand != ShorthandId::All {
1207                            // All is special because it contains both physical
1208                            // and logical longhands.
1209                            if let Some(g) = longhand.logical_group() {
1210                                logical_groups.insert(g);
1211                            }
1212                            seen.insert(longhand);
1213                            if seen == longhands {
1214                                break;
1215                            }
1216                        }
1217                    } else if saw_one
1218                        && let Some(g) = longhand.logical_group()
1219                        && logical_groups.contains(g)
1220                    {
1221                        logical_mismatch = true;
1222                        break;
1223                    }
1224                }
1225
1226                // 3.4.5:
1227                //     If there is one or more CSS declarations in current
1228                //     longhands have their important flag set and one or more
1229                //     with it unset, continue with the steps labeled shorthand
1230                //     loop.
1231                let is_important = important_count > 0;
1232                if is_important && important_count != current_longhands.len() {
1233                    continue;
1234                }
1235
1236                // 3.4.6:
1237                //    If there’s any declaration in declaration block in between
1238                //    the first and the last longhand in current longhands which
1239                //    belongs to the same logical property group, but has a
1240                //    different mapping logic as any of the longhands in current
1241                //    longhands, and is not in current longhands, continue with
1242                //    the steps labeled shorthand loop.
1243                if logical_mismatch {
1244                    continue;
1245                }
1246
1247                let importance = if is_important {
1248                    Importance::Important
1249                } else {
1250                    Importance::Normal
1251                };
1252
1253                // 3.4.7:
1254                //    Let value be the result of invoking serialize a CSS value
1255                //    of current longhands.
1256                let appendable_value =
1257                    match shorthand.get_shorthand_appendable_value(&current_longhands) {
1258                        None => continue,
1259                        Some(appendable_value) => appendable_value,
1260                    };
1261
1262                // We avoid re-serializing if we're already an
1263                // AppendableValue::Css.
1264                let mut v = CssString::new();
1265                let value = match appendable_value {
1266                    AppendableValue::Css(css) => {
1267                        debug_assert!(!css.is_empty());
1268                        appendable_value
1269                    },
1270                    other => {
1271                        append_declaration_value(&mut v, other)?;
1272
1273                        // 3.4.8:
1274                        //     If value is the empty string, continue with the
1275                        //     steps labeled shorthand loop.
1276                        if v.is_empty() {
1277                            continue;
1278                        }
1279
1280                        AppendableValue::Css({
1281                            // Safety: serialization only generates valid utf-8.
1282                            #[cfg(feature = "gecko")]
1283                            unsafe {
1284                                v.as_str_unchecked()
1285                            }
1286                            #[cfg(feature = "servo")]
1287                            &v
1288                        })
1289                    },
1290                };
1291
1292                // 3.4.9:
1293                //     Let serialized declaration be the result of invoking
1294                //     serialize a CSS declaration with property name shorthand,
1295                //     value value, and the important flag set if the CSS
1296                //     declarations in current longhands have their important
1297                //     flag set.
1298                //
1299                // 3.4.10:
1300                //     Append serialized declaration to list.
1301                append_serialization(
1302                    dest,
1303                    &shorthand,
1304                    value,
1305                    importance,
1306                    &mut is_first_serialization,
1307                )?;
1308
1309                // 3.4.11:
1310                //     Append the property names of all items of current
1311                //     longhands to already serialized.
1312                for current_longhand in &current_longhands {
1313                    let longhand_id = match current_longhand.id() {
1314                        PropertyDeclarationId::Longhand(id) => id,
1315                        PropertyDeclarationId::Custom(..) => unreachable!(),
1316                    };
1317
1318                    // Substep 9
1319                    already_serialized.insert(longhand_id.into());
1320                }
1321
1322                // 3.4.12:
1323                //     Continue with the steps labeled declaration loop.
1324                continue 'declaration_loop;
1325            }
1326
1327            // Steps 3.5, 3.6 & 3.7:
1328            //     Let value be the result of invoking serialize a CSS value of
1329            //     declaration.
1330            //
1331            //     Let serialized declaration be the result of invoking
1332            //     serialize a CSS declaration with property name property,
1333            //     value value, and the important flag set if declaration has
1334            //     its important flag set.
1335            //
1336            //     Append serialized declaration to list.
1337            append_serialization(
1338                dest,
1339                &property,
1340                AppendableValue::Declaration(declaration),
1341                importance,
1342                &mut is_first_serialization,
1343            )?;
1344
1345            // Step 3.8:
1346            //     Append property to already serialized.
1347            already_serialized.insert(longhand_id.into());
1348        }
1349
1350        // Step 4
1351        Ok(())
1352    }
1353}
1354
1355/// A convenient enum to represent different kinds of stuff that can represent a
1356/// _value_ in the serialization of a property declaration.
1357pub enum AppendableValue<'a, 'b: 'a> {
1358    /// A given declaration, of which we'll serialize just the value.
1359    Declaration(&'a PropertyDeclaration),
1360    /// A set of declarations for a given shorthand.
1361    ///
1362    /// FIXME: This needs more docs, where are the shorthands expanded? We print
1363    /// the property name before-hand, don't we?
1364    DeclarationsForShorthand(ShorthandId, &'a [&'b PropertyDeclaration]),
1365    /// A raw CSS string, coming for example from a property with CSS variables,
1366    /// or when storing a serialized shorthand value before appending directly.
1367    Css(&'a str),
1368}
1369
1370/// Potentially appends whitespace after the first (property: value;) pair.
1371fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result
1372where
1373    W: Write,
1374{
1375    if !*is_first_serialization {
1376        dest.write_char(' ')
1377    } else {
1378        *is_first_serialization = false;
1379        Ok(())
1380    }
1381}
1382
1383/// Append a given kind of appendable value to a serialization.
1384pub fn append_declaration_value<'a, 'b: 'a>(
1385    dest: &mut CssStringWriter,
1386    appendable_value: AppendableValue<'a, 'b>,
1387) -> fmt::Result {
1388    match appendable_value {
1389        AppendableValue::Css(css) => dest.write_str(css),
1390        AppendableValue::Declaration(decl) => decl.to_css(dest),
1391        AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
1392            shorthand.longhands_to_css(decls, dest)
1393        },
1394    }
1395}
1396
1397/// Append a given property and value pair to a serialization.
1398pub fn append_serialization<'a, 'b: 'a, N>(
1399    dest: &mut CssStringWriter,
1400    property_name: &N,
1401    appendable_value: AppendableValue<'a, 'b>,
1402    importance: Importance,
1403    is_first_serialization: &mut bool,
1404) -> fmt::Result
1405where
1406    N: ToCss,
1407{
1408    handle_first_serialization(dest, is_first_serialization)?;
1409
1410    property_name.to_css(&mut CssWriter::new(dest))?;
1411    dest.write_str(": ")?;
1412
1413    append_declaration_value(dest, appendable_value)?;
1414
1415    if importance.important() {
1416        dest.write_str(" !important")?;
1417    }
1418
1419    dest.write_char(';')
1420}
1421
1422/// A helper to parse the style attribute of an element, in order for this to be
1423/// shared between Servo and Gecko.
1424///
1425/// Inline because we call this cross-crate.
1426#[inline]
1427pub fn parse_style_attribute(
1428    input: &str,
1429    url_data: &UrlExtraData,
1430    error_reporter: Option<&dyn ParseErrorReporter>,
1431    quirks_mode: QuirksMode,
1432    rule_type: CssRuleType,
1433) -> PropertyDeclarationBlock {
1434    let mut context = ParserContext::new(
1435        Origin::Author,
1436        url_data,
1437        Some(rule_type),
1438        ParsingMode::DEFAULT,
1439        quirks_mode,
1440        /* namespaces = */ Default::default(),
1441        error_reporter,
1442        None,
1443        /* attr_taint */ Default::default(),
1444    );
1445
1446    parse_property_declaration_list(&mut context, &mut Parser::new(input), &[])
1447}
1448
1449/// Parse a given property declaration. Can result in multiple
1450/// `PropertyDeclaration`s when expanding a shorthand, for example.
1451///
1452/// This does not attempt to parse !important at all.
1453#[inline]
1454pub fn parse_one_declaration_into(
1455    declarations: &mut SourcePropertyDeclaration,
1456    id: PropertyId,
1457    input: &str,
1458    origin: Origin,
1459    url_data: &UrlExtraData,
1460    error_reporter: Option<&dyn ParseErrorReporter>,
1461    parsing_mode: ParsingMode,
1462    quirks_mode: QuirksMode,
1463    rule_type: CssRuleType,
1464) -> Result<(), ()> {
1465    let mut context = ParserContext::new(
1466        origin,
1467        url_data,
1468        Some(rule_type),
1469        parsing_mode,
1470        quirks_mode,
1471        /* namespaces = */ Default::default(),
1472        error_reporter,
1473        None,
1474        /* attr_taint */ Default::default(),
1475    );
1476
1477    let property_id_for_error_reporting = if context.error_reporting_enabled() {
1478        Some(id.clone())
1479    } else {
1480        None
1481    };
1482
1483    let mut parser = Parser::new(input);
1484    let start_position = parser.position();
1485    let start_location = parser.current_source_location();
1486    parser
1487        .parse_entirely(|parser| {
1488            PropertyDeclaration::parse_into(declarations, id, &mut context, parser)
1489        })
1490        .map_err(|err| {
1491            if context.error_reporting_enabled() {
1492                report_one_css_error(
1493                    &context,
1494                    None,
1495                    &[],
1496                    err,
1497                    parser.slice_from(start_position),
1498                    start_location,
1499                    property_id_for_error_reporting,
1500                )
1501            }
1502        })
1503}
1504
1505/// A struct to parse property declarations.
1506struct PropertyDeclarationParser<'a, 'b: 'a, 'i> {
1507    context: &'a mut ParserContext<'b>,
1508    state: &'a mut DeclarationParserState<'i>,
1509}
1510
1511/// The state needed to parse a declaration block.
1512///
1513/// It stores declarations in output_block.
1514#[derive(Default)]
1515pub struct DeclarationParserState<'i> {
1516    /// The output block where results are stored.
1517    output_block: PropertyDeclarationBlock,
1518    /// Declarations from the last declaration parsed. (note that a shorthand might expand to
1519    /// multiple declarations).
1520    declarations: SourcePropertyDeclaration,
1521    /// The importance from the last declaration parsed.
1522    importance: Importance,
1523    /// A list of errors that have happened so far. Not all of them might be reported.
1524    errors: SmallParseErrorVec<'i>,
1525    /// The start of the first declaration
1526    first_declaration_start: SourceLocation,
1527    /// The last parsed property id, if any.
1528    last_parsed_property_id: Option<PropertyId>,
1529}
1530
1531impl<'i> DeclarationParserState<'i> {
1532    /// Getter for first_declaration_start.
1533    pub fn first_declaration_start(&self) -> SourceLocation {
1534        self.first_declaration_start
1535    }
1536
1537    /// Returns whether any parsed declarations have been parsed so far.
1538    pub fn has_parsed_declarations(&self) -> bool {
1539        !self.output_block.is_empty()
1540    }
1541
1542    /// Takes the parsed declarations.
1543    pub fn take_declarations(&mut self) -> PropertyDeclarationBlock {
1544        std::mem::take(&mut self.output_block)
1545    }
1546
1547    /// Parse a single declaration value.
1548    pub fn parse_value(
1549        &mut self,
1550        context: &mut ParserContext,
1551        name: CowRcStr<'i>,
1552        input: &mut Parser<'i>,
1553        declaration_start: &ParserState,
1554    ) -> Result<(), ParseError> {
1555        let id = match PropertyId::parse(&name, context) {
1556            Ok(id) => id,
1557            Err(..) => {
1558                return Err(ParseError::custom(StyleParseErrorKind::UnknownProperty));
1559            },
1560        };
1561        if context.error_reporting_enabled() {
1562            self.last_parsed_property_id = Some(id.clone());
1563        }
1564        input.parse_until_before(Delimiter::Bang, |input| {
1565            PropertyDeclaration::parse_into(&mut self.declarations, id, context, input)
1566        })?;
1567        self.importance = match input.try_parse(parse_important) {
1568            Ok(()) => {
1569                if !context.allows_important_declarations() {
1570                    return Err(ParseError::custom(
1571                        StyleParseErrorKind::UnexpectedImportantDeclaration,
1572                    ));
1573                }
1574                Importance::Important
1575            },
1576            Err(_) => Importance::Normal,
1577        };
1578        // In case there is still unparsed text in the declaration, we should roll back.
1579        input.expect_exhausted()?;
1580        let has_parsed_declarations = self.has_parsed_declarations();
1581        self.output_block
1582            .extend(self.declarations.drain(), self.importance);
1583        // We've successfully parsed a declaration, so forget about
1584        // `last_parsed_property_id`. It'd be wrong to associate any
1585        // following error with this property.
1586        self.last_parsed_property_id = None;
1587
1588        if !has_parsed_declarations {
1589            self.first_declaration_start = declaration_start.source_location();
1590        }
1591
1592        Ok(())
1593    }
1594
1595    /// Reports any CSS errors that have ocurred if needed.
1596    #[inline]
1597    pub fn report_errors_if_needed(
1598        &mut self,
1599        context: &ParserContext,
1600        selectors: &[SelectorList<SelectorImpl>],
1601    ) {
1602        if self.errors.is_empty() {
1603            return;
1604        }
1605        self.do_report_css_errors(context, selectors);
1606    }
1607
1608    #[cold]
1609    fn do_report_css_errors(
1610        &mut self,
1611        context: &ParserContext,
1612        selectors: &[SelectorList<SelectorImpl>],
1613    ) {
1614        for (error, slice, location, property) in self.errors.drain(..) {
1615            report_one_css_error(
1616                context,
1617                Some(&self.output_block),
1618                selectors,
1619                error,
1620                slice,
1621                location,
1622                property,
1623            )
1624        }
1625    }
1626
1627    /// Resets the declaration parser state, and reports the error if needed.
1628    #[inline]
1629    pub fn did_error(
1630        &mut self,
1631        context: &ParserContext,
1632        error: ParseError,
1633        slice: &'i str,
1634        location: SourceLocation,
1635    ) {
1636        self.declarations.clear();
1637        if !context.error_reporting_enabled() {
1638            return;
1639        }
1640        let property = self.last_parsed_property_id.take();
1641        self.errors.push((error, slice, location, property));
1642    }
1643}
1644
1645/// Default methods reject all at rules.
1646impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1647    type Prelude = ();
1648    type AtRule = ();
1649    type Error = StyleParseErrorKind;
1650}
1651
1652/// Default methods reject all rules.
1653impl<'a, 'b, 'i> QualifiedRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1654    type Prelude = ();
1655    type QualifiedRule = ();
1656    type Error = StyleParseErrorKind;
1657}
1658
1659/// Based on NonMozillaVendorIdentifier from Gecko's CSS parser.
1660fn is_non_mozilla_vendor_identifier(name: &str) -> bool {
1661    (name.starts_with("-") && !name.starts_with("-moz-")) || name.starts_with("_")
1662}
1663
1664impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1665    type Declaration = ();
1666    type Error = StyleParseErrorKind;
1667
1668    fn parse_value(
1669        &mut self,
1670        name: CowRcStr<'i>,
1671        input: &mut Parser<'i>,
1672        declaration_start: &ParserState,
1673    ) -> Result<(), ParseError> {
1674        self.state
1675            .parse_value(self.context, name, input, declaration_start)
1676    }
1677}
1678
1679impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind>
1680    for PropertyDeclarationParser<'a, 'b, 'i>
1681{
1682    fn parse_declarations(&self) -> bool {
1683        true
1684    }
1685    // TODO(emilio): Nesting.
1686    fn parse_qualified(&self) -> bool {
1687        false
1688    }
1689}
1690
1691type SmallParseErrorVec<'i> =
1692    SmallVec<[(ParseError, &'i str, SourceLocation, Option<PropertyId>); 2]>;
1693
1694fn alias_of_known_property(name: &str) -> Option<PropertyId> {
1695    let mut prefixed = String::with_capacity(name.len() + 5);
1696    prefixed.push_str("-moz-");
1697    prefixed.push_str(name);
1698    PropertyId::parse_enabled_for_all_content(&prefixed).ok()
1699}
1700
1701#[cold]
1702fn report_one_css_error(
1703    context: &ParserContext,
1704    block: Option<&PropertyDeclarationBlock>,
1705    selectors: &[SelectorList<SelectorImpl>],
1706    mut error: ParseError,
1707    slice: &str,
1708    location: SourceLocation,
1709    property: Option<PropertyId>,
1710) {
1711    debug_assert!(context.error_reporting_enabled());
1712
1713    fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool {
1714        match property.as_shorthand() {
1715            Ok(id) => id
1716                .longhands()
1717                .all(|longhand| block.contains(PropertyDeclarationId::Longhand(longhand))),
1718            Err(longhand_or_custom) => block.contains(longhand_or_custom),
1719        }
1720    }
1721
1722    let mut error_string = Cow::Borrowed(slice);
1723    if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty) = error.kind {
1724        // The error no longer carries the property name, but `slice` is the
1725        // declaration text, i.e. `<name>: <value>`.
1726        let name = slice.split(':').next().unwrap_or("").trim();
1727        if is_non_mozilla_vendor_identifier(name) {
1728            // If the unrecognized property looks like a vendor-specific property,
1729            // silently ignore it instead of polluting the error output.
1730            return;
1731        }
1732        if let Some(alias) = alias_of_known_property(name) {
1733            // This is an unknown property, but its -moz-* version is known.
1734            // We don't want to report error if the -moz-* version is already
1735            // specified.
1736            if let Some(block) = block
1737                && all_properties_in_block(block, &alias)
1738            {
1739                return;
1740            }
1741        }
1742        if !name.is_empty() {
1743            // We don't care about the whole declaration, just the property name
1744            error_string = Cow::Borrowed(name);
1745        }
1746    }
1747
1748    if let Some(ref property) = property {
1749        if let Some(block) = block
1750            && all_properties_in_block(block, property)
1751        {
1752            return;
1753        }
1754        // Was able to parse property ID - Either an invalid value, or is constrained
1755        // by the rule block it's in to be invalid. In the former case, we need to unwrap
1756        // the error to be more specific.
1757        if !matches!(
1758            error.kind,
1759            ParseErrorKind::Custom(StyleParseErrorKind::UnexpectedImportantDeclaration)
1760        ) {
1761            error = ParseError::custom(StyleParseErrorKind::OtherInvalidValue);
1762        }
1763        if !slice.contains(':') {
1764            // For CSSOM we only have the value. If there's no `:`, prepend the property name.
1765            error_string = Cow::Owned(format!("{}: {slice}", property.to_css_string()));
1766        }
1767    }
1768
1769    let error =
1770        ContextualParseError::UnsupportedPropertyDeclaration(&error_string, error, selectors);
1771    context.log_css_error(location, error);
1772}
1773
1774/// Parse a list of property declarations and return a property declaration
1775/// block.
1776pub fn parse_property_declaration_list(
1777    context: &mut ParserContext,
1778    input: &mut Parser,
1779    selectors: &[SelectorList<SelectorImpl>],
1780) -> PropertyDeclarationBlock {
1781    let mut state = DeclarationParserState::default();
1782    let mut parser = PropertyDeclarationParser {
1783        context,
1784        state: &mut state,
1785    };
1786    let mut iter = RuleBodyParser::new(input, &mut parser);
1787    while let Some(declaration) = iter.next() {
1788        match declaration {
1789            Ok(()) => {},
1790            Err((error, slice, location)) => {
1791                let parser = &mut *iter.parser;
1792                parser
1793                    .state
1794                    .did_error(parser.context, error, slice, location)
1795            },
1796        }
1797    }
1798    parser
1799        .state
1800        .report_errors_if_needed(parser.context, selectors);
1801    state.output_block
1802}