style/properties/
declaration_block.rs

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