Skip to main content

style/properties/
declaration_block.rs

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