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