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