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