tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

declaration_block.rs (62975B)


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