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        /* attr_taint */ Default::default(),
1394    );
1395
1396    let mut input = ParserInput::new(input);
1397    parse_property_declaration_list(&context, &mut Parser::new(&mut input), &[])
1398}
1399
1400/// Parse a given property declaration. Can result in multiple
1401/// `PropertyDeclaration`s when expanding a shorthand, for example.
1402///
1403/// This does not attempt to parse !important at all.
1404#[inline]
1405pub fn parse_one_declaration_into(
1406    declarations: &mut SourcePropertyDeclaration,
1407    id: PropertyId,
1408    input: &str,
1409    origin: Origin,
1410    url_data: &UrlExtraData,
1411    error_reporter: Option<&dyn ParseErrorReporter>,
1412    parsing_mode: ParsingMode,
1413    quirks_mode: QuirksMode,
1414    rule_type: CssRuleType,
1415) -> Result<(), ()> {
1416    let context = ParserContext::new(
1417        origin,
1418        url_data,
1419        Some(rule_type),
1420        parsing_mode,
1421        quirks_mode,
1422        /* namespaces = */ Default::default(),
1423        error_reporter,
1424        None,
1425        /* attr_taint */ Default::default(),
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}