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