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