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