Bug 1642261 - Part 2: Add telemetry for -moz-appearance usage. r=emilio
[gecko.git] / servo / components / style / properties / declaration_block.rs
blobe30b2229b9c75f6fbff6de4e44ce3e8d73017589
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/. */
5 //! A property declaration block.
7 #![deny(missing_docs)]
9 use super::*;
10 use crate::context::QuirksMode;
11 use crate::custom_properties::CustomPropertiesBuilder;
12 use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
13 use crate::parser::ParserContext;
14 use crate::properties::animated_properties::{AnimationValue, AnimationValueMap};
15 use crate::selector_parser::SelectorImpl;
16 use crate::shared_lock::Locked;
17 use crate::str::{CssString, CssStringBorrow, CssStringWriter};
18 use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
19 use crate::values::computed::Context;
20 use cssparser::{parse_important, CowRcStr, DeclarationListParser, ParserInput};
21 use cssparser::{AtRuleParser, DeclarationParser, Delimiter, ParseErrorKind, Parser};
22 use itertools::Itertools;
23 use selectors::SelectorList;
24 use smallbitvec::{self, SmallBitVec};
25 use smallvec::SmallVec;
26 use std::fmt::{self, Write};
27 use std::iter::{DoubleEndedIterator, Zip};
28 use std::slice::Iter;
29 use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
31 /// The animation rules.
32 ///
33 /// The first one is for Animation cascade level, and the second one is for
34 /// Transition cascade level.
35 pub struct AnimationRules(
36     pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
37     pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
40 impl AnimationRules {
41     /// Returns whether these animation rules represents an actual rule or not.
42     pub fn is_empty(&self) -> bool {
43         self.0.is_none() && self.1.is_none()
44     }
47 /// An enum describes how a declaration should update
48 /// the declaration block.
49 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
50 enum DeclarationUpdate {
51     /// The given declaration doesn't update anything.
52     None,
53     /// The given declaration is new, and should be append directly.
54     Append,
55     /// The given declaration can be updated in-place at the given position.
56     UpdateInPlace { pos: usize },
57     /// The given declaration cannot be updated in-place, and an existing
58     /// one needs to be removed at the given position.
59     AppendAndRemove { pos: usize },
62 /// A struct describes how a declaration block should be updated by
63 /// a `SourcePropertyDeclaration`.
64 #[derive(Default)]
65 pub struct SourcePropertyDeclarationUpdate {
66     updates: SubpropertiesVec<DeclarationUpdate>,
67     new_count: usize,
68     any_removal: bool,
71 /// A declaration [importance][importance].
72 ///
73 /// [importance]: https://drafts.csswg.org/css-cascade/#importance
74 #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
75 pub enum Importance {
76     /// Indicates a declaration without `!important`.
77     Normal,
79     /// Indicates a declaration with `!important`.
80     Important,
83 impl Importance {
84     /// Return whether this is an important declaration.
85     pub fn important(self) -> bool {
86         match self {
87             Importance::Normal => false,
88             Importance::Important => true,
89         }
90     }
93 /// Overridden declarations are skipped.
94 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
95 #[derive(Clone, ToShmem)]
96 pub struct PropertyDeclarationBlock {
97     /// The group of declarations, along with their importance.
98     ///
99     /// Only deduplicated declarations appear here.
100     declarations: Vec<PropertyDeclaration>,
102     /// The "important" flag for each declaration in `declarations`.
103     declarations_importance: SmallBitVec,
105     longhands: LonghandIdSet,
108 /// Iterator over `(PropertyDeclaration, Importance)` pairs.
109 pub struct DeclarationImportanceIterator<'a> {
110     iter: Zip<Iter<'a, PropertyDeclaration>, smallbitvec::Iter<'a>>,
113 impl<'a> Default for DeclarationImportanceIterator<'a> {
114     fn default() -> Self {
115         Self {
116             iter: [].iter().zip(smallbitvec::Iter::default()),
117         }
118     }
121 impl<'a> DeclarationImportanceIterator<'a> {
122     /// Constructor.
123     fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
124         DeclarationImportanceIterator {
125             iter: declarations.iter().zip(important.iter()),
126         }
127     }
130 impl<'a> Iterator for DeclarationImportanceIterator<'a> {
131     type Item = (&'a PropertyDeclaration, Importance);
133     #[inline]
134     fn next(&mut self) -> Option<Self::Item> {
135         self.iter.next().map(|(decl, important)| {
136             (
137                 decl,
138                 if important {
139                     Importance::Important
140                 } else {
141                     Importance::Normal
142                 },
143             )
144         })
145     }
147     #[inline]
148     fn size_hint(&self) -> (usize, Option<usize>) {
149         self.iter.size_hint()
150     }
153 impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
154     #[inline(always)]
155     fn next_back(&mut self) -> Option<Self::Item> {
156         self.iter.next_back().map(|(decl, important)| {
157             (
158                 decl,
159                 if important {
160                     Importance::Important
161                 } else {
162                     Importance::Normal
163                 },
164             )
165         })
166     }
169 /// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
170 pub struct AnimationValueIterator<'a, 'cx, 'cx_a: 'cx> {
171     iter: DeclarationImportanceIterator<'a>,
172     context: &'cx mut Context<'cx_a>,
173     default_values: &'a ComputedValues,
174     /// Custom properties in a keyframe if exists.
175     extra_custom_properties: Option<&'a Arc<crate::custom_properties::CustomPropertiesMap>>,
178 impl<'a, 'cx, 'cx_a: 'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
179     fn new(
180         declarations: &'a PropertyDeclarationBlock,
181         context: &'cx mut Context<'cx_a>,
182         default_values: &'a ComputedValues,
183         extra_custom_properties: Option<&'a Arc<crate::custom_properties::CustomPropertiesMap>>,
184     ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
185         AnimationValueIterator {
186             iter: declarations.declaration_importance_iter(),
187             context,
188             default_values,
189             extra_custom_properties,
190         }
191     }
194 impl<'a, 'cx, 'cx_a: 'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
195     type Item = AnimationValue;
196     #[inline]
197     fn next(&mut self) -> Option<Self::Item> {
198         loop {
199             let (decl, importance) = self.iter.next()?;
201             if importance.important() {
202                 continue;
203             }
205             let animation = AnimationValue::from_declaration(
206                 decl,
207                 &mut self.context,
208                 self.extra_custom_properties,
209                 self.default_values,
210             );
212             if let Some(anim) = animation {
213                 return Some(anim);
214             }
215         }
216     }
219 impl fmt::Debug for PropertyDeclarationBlock {
220     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221         self.declarations.fmt(f)
222     }
225 impl PropertyDeclarationBlock {
226     /// Returns the number of declarations in the block.
227     #[inline]
228     pub fn len(&self) -> usize {
229         self.declarations.len()
230     }
232     /// Create an empty block
233     #[inline]
234     pub fn new() -> Self {
235         PropertyDeclarationBlock {
236             declarations: Vec::new(),
237             declarations_importance: SmallBitVec::new(),
238             longhands: LonghandIdSet::new(),
239         }
240     }
242     /// Create a block with a single declaration
243     pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
244         let mut longhands = LonghandIdSet::new();
245         if let PropertyDeclarationId::Longhand(id) = declaration.id() {
246             longhands.insert(id);
247         }
248         PropertyDeclarationBlock {
249             declarations: vec![declaration],
250             declarations_importance: SmallBitVec::from_elem(1, importance.important()),
251             longhands,
252         }
253     }
255     /// The declarations in this block
256     #[inline]
257     pub fn declarations(&self) -> &[PropertyDeclaration] {
258         &self.declarations
259     }
261     /// The `important` flags for declarations in this block
262     #[inline]
263     pub fn declarations_importance(&self) -> &SmallBitVec {
264         &self.declarations_importance
265     }
267     /// Iterate over `(PropertyDeclaration, Importance)` pairs
268     #[inline]
269     pub fn declaration_importance_iter(&self) -> DeclarationImportanceIterator {
270         DeclarationImportanceIterator::new(&self.declarations, &self.declarations_importance)
271     }
273     /// Iterate over `PropertyDeclaration` for Importance::Normal
274     #[inline]
275     pub fn normal_declaration_iter<'a>(
276         &'a self,
277     ) -> impl DoubleEndedIterator<Item = &'a PropertyDeclaration> {
278         self.declaration_importance_iter()
279             .filter(|(_, importance)| !importance.important())
280             .map(|(declaration, _)| declaration)
281     }
283     /// Return an iterator of (AnimatableLonghand, AnimationValue).
284     #[inline]
285     pub fn to_animation_value_iter<'a, 'cx, 'cx_a: 'cx>(
286         &'a self,
287         context: &'cx mut Context<'cx_a>,
288         default_values: &'a ComputedValues,
289         extra_custom_properties: Option<&'a Arc<crate::custom_properties::CustomPropertiesMap>>,
290     ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
291         AnimationValueIterator::new(self, context, default_values, extra_custom_properties)
292     }
294     /// Returns whether this block contains any declaration with `!important`.
295     ///
296     /// This is based on the `declarations_importance` bit-vector,
297     /// which should be maintained whenever `declarations` is changed.
298     #[inline]
299     pub fn any_important(&self) -> bool {
300         !self.declarations_importance.all_false()
301     }
303     /// Returns whether this block contains any declaration without `!important`.
304     ///
305     /// This is based on the `declarations_importance` bit-vector,
306     /// which should be maintained whenever `declarations` is changed.
307     #[inline]
308     pub fn any_normal(&self) -> bool {
309         !self.declarations_importance.all_true()
310     }
312     /// Returns whether this block contains a declaration of a given longhand.
313     #[inline]
314     pub fn contains(&self, id: LonghandId) -> bool {
315         self.longhands.contains(id)
316     }
318     /// Returns whether this block contains any reset longhand.
319     #[inline]
320     pub fn contains_any_reset(&self) -> bool {
321         self.longhands.contains_any_reset()
322     }
324     /// Get a declaration for a given property.
325     ///
326     /// NOTE: This is linear time in the case of custom properties or in the
327     /// case the longhand is actually in the declaration block.
328     #[inline]
329     pub fn get(
330         &self,
331         property: PropertyDeclarationId,
332     ) -> Option<(&PropertyDeclaration, Importance)> {
333         if let PropertyDeclarationId::Longhand(id) = property {
334             if !self.contains(id) {
335                 return None;
336             }
337         }
339         self.declaration_importance_iter()
340             .find(|(declaration, _)| declaration.id() == property)
341     }
343     /// Get a declaration for a given property with the specified importance.
344     #[inline]
345     pub fn get_at_importance(
346         &self,
347         property: PropertyDeclarationId,
348         importance: Importance,
349     ) -> Option<&PropertyDeclaration> {
350         let (declaration, i) = self.get(property)?;
351         if i == importance {
352             Some(declaration)
353         } else {
354             None
355         }
356     }
358     /// Tries to serialize a given shorthand from the declarations in this
359     /// block.
360     pub fn shorthand_to_css(
361         &self,
362         shorthand: ShorthandId,
363         dest: &mut CssStringWriter,
364     ) -> fmt::Result {
365         // Step 1.2.1 of
366         // https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue
367         let mut list = SmallVec::<[&_; 10]>::new();
368         let mut important_count = 0;
370         // Step 1.2.2
371         for longhand in shorthand.longhands() {
372             // Step 1.2.2.1
373             let declaration = self.get(PropertyDeclarationId::Longhand(longhand));
375             // Step 1.2.2.2 & 1.2.2.3
376             match declaration {
377                 Some((declaration, importance)) => {
378                     list.push(declaration);
379                     if importance.important() {
380                         important_count += 1;
381                     }
382                 },
383                 None => return Ok(()),
384             }
385         }
387         // If there is one or more longhand with important, and one or more
388         // without important, we don't serialize it as a shorthand.
389         if important_count > 0 && important_count != list.len() {
390             return Ok(());
391         }
393         // Step 1.2.3
394         // We don't print !important when serializing individual properties,
395         // so we treat this as a normal-importance property
396         match shorthand.get_shorthand_appendable_value(list.iter().cloned()) {
397             Some(appendable_value) => append_declaration_value(dest, appendable_value),
398             None => return Ok(()),
399         }
400     }
402     /// Find the value of the given property in this block and serialize it
403     ///
404     /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertyvalue>
405     pub fn property_value_to_css(
406         &self,
407         property: &PropertyId,
408         dest: &mut CssStringWriter,
409     ) -> fmt::Result {
410         // Step 1.1: done when parsing a string to PropertyId
412         // Step 1.2
413         let longhand_or_custom = match property.as_shorthand() {
414             Ok(shorthand) => return self.shorthand_to_css(shorthand, dest),
415             Err(longhand_or_custom) => longhand_or_custom,
416         };
418         if let Some((value, _importance)) = self.get(longhand_or_custom) {
419             // Step 2
420             value.to_css(dest)
421         } else {
422             // Step 3
423             Ok(())
424         }
425     }
427     /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-getpropertypriority>
428     pub fn property_priority(&self, property: &PropertyId) -> Importance {
429         // Step 1: done when parsing a string to PropertyId
431         // Step 2
432         match property.as_shorthand() {
433             Ok(shorthand) => {
434                 // Step 2.1 & 2.2 & 2.3
435                 if shorthand.longhands().all(|l| {
436                     self.get(PropertyDeclarationId::Longhand(l))
437                         .map_or(false, |(_, importance)| importance.important())
438                 }) {
439                     Importance::Important
440                 } else {
441                     Importance::Normal
442                 }
443             },
444             Err(longhand_or_custom) => {
445                 // Step 3
446                 self.get(longhand_or_custom)
447                     .map_or(Importance::Normal, |(_, importance)| importance)
448             },
449         }
450     }
452     /// Returns whether the property is definitely new for this declaration
453     /// block. It returns true when the declaration is a non-custom longhand
454     /// and it doesn't exist in the block, and returns false otherwise.
455     #[inline]
456     fn is_definitely_new(&self, decl: &PropertyDeclaration) -> bool {
457         decl.id()
458             .as_longhand()
459             .map_or(false, |id| !self.longhands.contains(id))
460     }
462     /// Adds or overrides the declaration for a given property in this block.
463     ///
464     /// See the documentation of `push` to see what impact `source` has when the
465     /// property is already there.
466     pub fn extend(
467         &mut self,
468         mut drain: SourcePropertyDeclarationDrain,
469         importance: Importance,
470     ) -> bool {
471         let all_shorthand_len = match drain.all_shorthand {
472             AllShorthand::NotSet => 0,
473             AllShorthand::CSSWideKeyword(_) | AllShorthand::WithVariables(_) => {
474                 shorthands::ALL_SHORTHAND_MAX_LEN
475             },
476         };
477         let push_calls_count = drain.declarations.len() + all_shorthand_len;
479         // With deduplication the actual length increase may be less than this.
480         self.declarations.reserve(push_calls_count);
482         let mut changed = false;
483         for decl in &mut drain.declarations {
484             changed |= self.push(decl, importance);
485         }
486         drain
487             .all_shorthand
488             .declarations()
489             .fold(changed, |changed, decl| {
490                 changed | self.push(decl, importance)
491             })
492     }
494     /// Adds or overrides the declaration for a given property in this block.
495     ///
496     /// Returns whether the declaration has changed.
497     ///
498     /// This is only used for parsing and internal use.
499     pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) -> bool {
500         if !self.is_definitely_new(&declaration) {
501             let mut index_to_remove = None;
502             for (i, slot) in self.declarations.iter_mut().enumerate() {
503                 if slot.id() != declaration.id() {
504                     continue;
505                 }
507                 let important = self.declarations_importance[i];
509                 // For declarations from parsing, non-important declarations
510                 // shouldn't override existing important one.
511                 if important && !importance.important() {
512                     return false;
513                 }
515                 index_to_remove = Some(i);
516                 break;
517             }
519             if let Some(index) = index_to_remove {
520                 self.declarations.remove(index);
521                 self.declarations_importance.remove(index);
522                 self.declarations.push(declaration);
523                 self.declarations_importance.push(importance.important());
524                 return true;
525             }
526         }
528         if let PropertyDeclarationId::Longhand(id) = declaration.id() {
529             self.longhands.insert(id);
530         }
531         self.declarations.push(declaration);
532         self.declarations_importance.push(importance.important());
533         true
534     }
536     /// Prepares updating this declaration block with the given
537     /// `SourcePropertyDeclaration` and importance, and returns whether
538     /// there is something to update.
539     pub fn prepare_for_update(
540         &self,
541         source_declarations: &SourcePropertyDeclaration,
542         importance: Importance,
543         updates: &mut SourcePropertyDeclarationUpdate,
544     ) -> bool {
545         debug_assert!(updates.updates.is_empty());
546         // Check whether we are updating for an all shorthand change.
547         if !matches!(source_declarations.all_shorthand, AllShorthand::NotSet) {
548             debug_assert!(source_declarations.declarations.is_empty());
549             return source_declarations
550                 .all_shorthand
551                 .declarations()
552                 .any(|decl| {
553                     self.is_definitely_new(&decl) ||
554                         self.declarations
555                             .iter()
556                             .enumerate()
557                             .find(|&(_, ref d)| d.id() == decl.id())
558                             .map_or(true, |(i, d)| {
559                                 let important = self.declarations_importance[i];
560                                 *d != decl || important != importance.important()
561                             })
562                 });
563         }
564         // Fill `updates` with update information.
565         let mut any_update = false;
566         let new_count = &mut updates.new_count;
567         let any_removal = &mut updates.any_removal;
568         let updates = &mut updates.updates;
569         updates.extend(
570             source_declarations
571                 .declarations
572                 .iter()
573                 .map(|declaration| {
574                     if self.is_definitely_new(declaration) {
575                         return DeclarationUpdate::Append;
576                     }
577                     let longhand_id = declaration.id().as_longhand();
578                     if let Some(longhand_id) = longhand_id {
579                         if let Some(logical_group) = longhand_id.logical_group() {
580                             let mut needs_append = false;
581                             for (pos, decl) in self.declarations.iter().enumerate().rev() {
582                                 let id = match decl.id().as_longhand() {
583                                     Some(id) => id,
584                                     None => continue,
585                                 };
586                                 if id == longhand_id {
587                                     if needs_append {
588                                         return DeclarationUpdate::AppendAndRemove { pos };
589                                     }
590                                     let important = self.declarations_importance[pos];
591                                     if decl == declaration && important == importance.important() {
592                                         return DeclarationUpdate::None;
593                                     }
594                                     return DeclarationUpdate::UpdateInPlace { pos };
595                                 }
596                                 if !needs_append &&
597                                     id.logical_group() == Some(logical_group) &&
598                                     id.is_logical() != longhand_id.is_logical()
599                                 {
600                                     needs_append = true;
601                                 }
602                             }
603                             unreachable!("Longhand should be found in loop above");
604                         }
605                     }
606                     self.declarations
607                         .iter()
608                         .enumerate()
609                         .find(|&(_, ref decl)| decl.id() == declaration.id())
610                         .map_or(DeclarationUpdate::Append, |(pos, decl)| {
611                             let important = self.declarations_importance[pos];
612                             if decl == declaration && important == importance.important() {
613                                 DeclarationUpdate::None
614                             } else {
615                                 DeclarationUpdate::UpdateInPlace { pos }
616                             }
617                         })
618                 })
619                 .inspect(|update| {
620                     if matches!(update, DeclarationUpdate::None) {
621                         return;
622                     }
623                     any_update = true;
624                     match update {
625                         DeclarationUpdate::Append => {
626                             *new_count += 1;
627                         },
628                         DeclarationUpdate::AppendAndRemove { .. } => {
629                             *any_removal = true;
630                         },
631                         _ => {},
632                     }
633                 }),
634         );
635         any_update
636     }
638     /// Update this declaration block with the given data.
639     pub fn update(
640         &mut self,
641         drain: SourcePropertyDeclarationDrain,
642         importance: Importance,
643         updates: &mut SourcePropertyDeclarationUpdate,
644     ) {
645         let important = importance.important();
646         if !matches!(drain.all_shorthand, AllShorthand::NotSet) {
647             debug_assert!(updates.updates.is_empty());
648             for decl in drain.all_shorthand.declarations() {
649                 if self.is_definitely_new(&decl) {
650                     let longhand_id = decl.id().as_longhand().unwrap();
651                     self.declarations.push(decl);
652                     self.declarations_importance.push(important);
653                     self.longhands.insert(longhand_id);
654                 } else {
655                     let (idx, slot) = self
656                         .declarations
657                         .iter_mut()
658                         .enumerate()
659                         .find(|&(_, ref d)| d.id() == decl.id())
660                         .unwrap();
661                     *slot = decl;
662                     self.declarations_importance.set(idx, important);
663                 }
664             }
665             return;
666         }
668         self.declarations.reserve(updates.new_count);
669         if updates.any_removal {
670             // Prepare for removal and fixing update positions.
671             struct UpdateOrRemoval<'a> {
672                 item: &'a mut DeclarationUpdate,
673                 pos: usize,
674                 remove: bool,
675             }
676             let mut updates_and_removals: SubpropertiesVec<UpdateOrRemoval> = updates
677                 .updates
678                 .iter_mut()
679                 .filter_map(|item| {
680                     let (pos, remove) = match *item {
681                         DeclarationUpdate::UpdateInPlace { pos } => (pos, false),
682                         DeclarationUpdate::AppendAndRemove { pos } => (pos, true),
683                         _ => return None,
684                     };
685                     Some(UpdateOrRemoval { item, pos, remove })
686                 })
687                 .collect();
688             // Execute removals. It's important to do it in reverse index order,
689             // so that removing doesn't invalidate following positions.
690             updates_and_removals.sort_unstable_by_key(|update| update.pos);
691             updates_and_removals
692                 .iter()
693                 .rev()
694                 .filter(|update| update.remove)
695                 .for_each(|update| {
696                     self.declarations.remove(update.pos);
697                     self.declarations_importance.remove(update.pos);
698                 });
699             // Fixup pos field for updates.
700             let mut removed_count = 0;
701             for update in updates_and_removals.iter_mut() {
702                 if update.remove {
703                     removed_count += 1;
704                     continue;
705                 }
706                 debug_assert_eq!(
707                     *update.item,
708                     DeclarationUpdate::UpdateInPlace { pos: update.pos }
709                 );
710                 *update.item = DeclarationUpdate::UpdateInPlace {
711                     pos: update.pos - removed_count,
712                 };
713             }
714         }
715         // Execute updates and appends.
716         for (decl, update) in drain.declarations.zip_eq(updates.updates.iter()) {
717             match *update {
718                 DeclarationUpdate::None => {},
719                 DeclarationUpdate::Append | DeclarationUpdate::AppendAndRemove { .. } => {
720                     if let Some(id) = decl.id().as_longhand() {
721                         self.longhands.insert(id);
722                     }
723                     self.declarations.push(decl);
724                     self.declarations_importance.push(important);
725                 },
726                 DeclarationUpdate::UpdateInPlace { pos } => {
727                     self.declarations[pos] = decl;
728                     self.declarations_importance.set(pos, important);
729                 },
730             }
731         }
732         updates.updates.clear();
733     }
735     /// Returns the first declaration that would be removed by removing
736     /// `property`.
737     #[inline]
738     pub fn first_declaration_to_remove(&self, property: &PropertyId) -> Option<usize> {
739         if let Some(id) = property.longhand_id() {
740             if !self.longhands.contains(id) {
741                 return None;
742             }
743         }
745         self.declarations
746             .iter()
747             .position(|declaration| declaration.id().is_or_is_longhand_of(property))
748     }
750     /// Removes a given declaration at a given index.
751     #[inline]
752     fn remove_declaration_at(&mut self, i: usize) {
753         {
754             let id = self.declarations[i].id();
755             if let PropertyDeclarationId::Longhand(id) = id {
756                 self.longhands.remove(id);
757             }
758             self.declarations_importance.remove(i);
759         }
760         self.declarations.remove(i);
761     }
763     /// <https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-removeproperty>
764     ///
765     /// `first_declaration` needs to be the result of
766     /// `first_declaration_to_remove`.
767     #[inline]
768     pub fn remove_property(&mut self, property: &PropertyId, first_declaration: usize) {
769         debug_assert_eq!(
770             Some(first_declaration),
771             self.first_declaration_to_remove(property)
772         );
773         debug_assert!(self.declarations[first_declaration]
774             .id()
775             .is_or_is_longhand_of(property));
777         self.remove_declaration_at(first_declaration);
779         let shorthand = match property.as_shorthand() {
780             Ok(s) => s,
781             Err(_longhand_or_custom) => return,
782         };
784         let mut i = first_declaration;
785         let mut len = self.len();
786         while i < len {
787             if !self.declarations[i].id().is_longhand_of(shorthand) {
788                 i += 1;
789                 continue;
790             }
792             self.remove_declaration_at(i);
793             len -= 1;
794         }
795     }
797     /// Take a declaration block known to contain a single property and serialize it.
798     pub fn single_value_to_css(
799         &self,
800         property: &PropertyId,
801         dest: &mut CssStringWriter,
802         computed_values: Option<&ComputedValues>,
803         custom_properties_block: Option<&PropertyDeclarationBlock>,
804         device: &Device,
805     ) -> fmt::Result {
806         if let Ok(shorthand) = property.as_shorthand() {
807             return self.shorthand_to_css(shorthand, dest);
808         }
810         // FIXME(emilio): Should this assert, or assert that the declaration is
811         // the property we expect?
812         let declaration = match self.declarations.get(0) {
813             Some(d) => d,
814             None => return Err(fmt::Error),
815         };
817         let custom_properties = if let Some(cv) = computed_values {
818             // If there are extra custom properties for this declaration block,
819             // factor them in too.
820             if let Some(block) = custom_properties_block {
821                 // FIXME(emilio): This is not super-efficient here, and all this
822                 // feels like a hack anyway...
823                 block.cascade_custom_properties(cv.custom_properties(), device)
824             } else {
825                 cv.custom_properties().cloned()
826             }
827         } else {
828             None
829         };
831         match (declaration, computed_values) {
832             // If we have a longhand declaration with variables, those variables
833             // will be stored as unparsed values.
834             //
835             // As a temporary measure to produce sensible results in Gecko's
836             // getKeyframes() implementation for CSS animations, if
837             // |computed_values| is supplied, we use it to expand such variable
838             // declarations. This will be fixed properly in Gecko bug 1391537.
839             (&PropertyDeclaration::WithVariables(ref declaration), Some(ref _computed_values)) => {
840                 declaration
841                     .value
842                     .substitute_variables(
843                         declaration.id,
844                         custom_properties.as_ref(),
845                         QuirksMode::NoQuirks,
846                         device,
847                     )
848                     .to_css(dest)
849             },
850             (ref d, _) => d.to_css(dest),
851         }
852     }
854     /// Convert AnimationValueMap to PropertyDeclarationBlock.
855     pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self {
856         let len = animation_value_map.len();
857         let mut declarations = Vec::with_capacity(len);
858         let mut longhands = LonghandIdSet::new();
860         for (property, animation_value) in animation_value_map.iter() {
861             longhands.insert(*property);
862             declarations.push(animation_value.uncompute());
863         }
865         PropertyDeclarationBlock {
866             declarations,
867             longhands,
868             declarations_importance: SmallBitVec::from_elem(len, false),
869         }
870     }
872     /// Returns true if the declaration block has a CSSWideKeyword for the given
873     /// property.
874     pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
875         if let Some(id) = property.longhand_id() {
876             if !self.longhands.contains(id) {
877                 return false;
878             }
879         }
880         self.declarations.iter().any(|decl| {
881             decl.id().is_or_is_longhand_of(property) && decl.get_css_wide_keyword().is_some()
882         })
883     }
885     /// Returns a custom properties map which is the result of cascading custom
886     /// properties in this declaration block along with context's custom
887     /// properties.
888     pub fn cascade_custom_properties_with_context(
889         &self,
890         context: &Context,
891     ) -> Option<Arc<crate::custom_properties::CustomPropertiesMap>> {
892         self.cascade_custom_properties(
893             context.style().custom_properties(),
894             context.device(),
895         )
896     }
898     /// Returns a custom properties map which is the result of cascading custom
899     /// properties in this declaration block along with the given custom
900     /// properties.
901     fn cascade_custom_properties(
902         &self,
903         inherited_custom_properties: Option<&Arc<crate::custom_properties::CustomPropertiesMap>>,
904         device: &Device,
905     ) -> Option<Arc<crate::custom_properties::CustomPropertiesMap>> {
906         let mut builder = CustomPropertiesBuilder::new(inherited_custom_properties, device);
908         for declaration in self.normal_declaration_iter() {
909             if let PropertyDeclaration::Custom(ref declaration) = *declaration {
910                 builder.cascade(declaration, Origin::Author);
911             }
912         }
914         builder.build()
915     }
917     /// Like the method on ToCss, but without the type parameter to avoid
918     /// accidentally monomorphizing this large function multiple times for
919     /// different writers.
920     ///
921     /// https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
922     pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
923         use std::iter::Cloned;
924         use std::slice;
926         let mut is_first_serialization = true; // trailing serializations should have a prepended space
928         // Step 1 -> dest = result list
930         // Step 2
931         //
932         // NOTE(emilio): We reuse this set for both longhands and shorthands
933         // with subtly different meaning. For longhands, only longhands that
934         // have actually been serialized (either by themselves, or as part of a
935         // shorthand) appear here. For shorthands, all the shorthands that we've
936         // attempted to serialize appear here.
937         let mut already_serialized = NonCustomPropertyIdSet::new();
939         // Step 3
940         for (declaration, importance) in self.declaration_importance_iter() {
941             // Step 3.1
942             let property = declaration.id();
943             let longhand_id = match property {
944                 PropertyDeclarationId::Longhand(id) => id,
945                 PropertyDeclarationId::Custom(..) => {
946                     // Given the invariants that there are no duplicate
947                     // properties in a declaration block, and that custom
948                     // properties can't be part of a shorthand, we can just care
949                     // about them here.
950                     append_serialization::<Cloned<slice::Iter<_>>, _>(
951                         dest,
952                         &property,
953                         AppendableValue::Declaration(declaration),
954                         importance,
955                         &mut is_first_serialization,
956                     )?;
957                     continue;
958                 },
959             };
961             // Step 3.2
962             if already_serialized.contains(longhand_id.into()) {
963                 continue;
964             }
966             // Step 3.3
967             // Step 3.3.1 is done by checking already_serialized while
968             // iterating below.
970             // Step 3.3.2
971             for shorthand in longhand_id.shorthands() {
972                 // We already attempted to serialize this shorthand before.
973                 if already_serialized.contains(shorthand.into()) {
974                     continue;
975                 }
976                 already_serialized.insert(shorthand.into());
978                 if shorthand.is_legacy_shorthand() {
979                     continue;
980                 }
982                 // Substep 2 & 3
983                 let mut current_longhands = SmallVec::<[_; 10]>::new();
984                 let mut important_count = 0;
985                 let mut found_system = None;
987                 let is_system_font = shorthand == ShorthandId::Font &&
988                     self.declarations.iter().any(|l| match l.id() {
989                         PropertyDeclarationId::Longhand(id) => {
990                             if already_serialized.contains(id.into()) {
991                                 return false;
992                             }
994                             l.get_system().is_some()
995                         },
996                         PropertyDeclarationId::Custom(..) => {
997                             debug_assert!(l.get_system().is_none());
998                             false
999                         },
1000                     });
1002                 if is_system_font {
1003                     for (longhand, importance) in self.declaration_importance_iter() {
1004                         if longhand.get_system().is_some() || longhand.is_default_line_height() {
1005                             current_longhands.push(longhand);
1006                             if found_system.is_none() {
1007                                 found_system = longhand.get_system();
1008                             }
1009                             if importance.important() {
1010                                 important_count += 1;
1011                             }
1012                         }
1013                     }
1014                 } else {
1015                     let mut contains_all_longhands = true;
1016                     for longhand in shorthand.longhands() {
1017                         match self.get(PropertyDeclarationId::Longhand(longhand)) {
1018                             Some((declaration, importance)) => {
1019                                 current_longhands.push(declaration);
1020                                 if importance.important() {
1021                                     important_count += 1;
1022                                 }
1023                             },
1024                             None => {
1025                                 contains_all_longhands = false;
1026                                 break;
1027                             },
1028                         }
1029                     }
1031                     // Substep 1:
1032                     if !contains_all_longhands {
1033                         continue;
1034                     }
1035                 }
1037                 // Substep 4
1038                 let is_important = important_count > 0;
1039                 if is_important && important_count != current_longhands.len() {
1040                     continue;
1041                 }
1042                 let importance = if is_important {
1043                     Importance::Important
1044                 } else {
1045                     Importance::Normal
1046                 };
1048                 // Substep 5 - Let value be the result of invoking serialize
1049                 // a CSS value of current longhands.
1050                 let appendable_value = match shorthand
1051                     .get_shorthand_appendable_value(current_longhands.iter().cloned())
1052                 {
1053                     None => continue,
1054                     Some(appendable_value) => appendable_value,
1055                 };
1057                 // We avoid re-serializing if we're already an
1058                 // AppendableValue::Css.
1059                 let mut v = CssString::new();
1060                 let value = match (appendable_value, found_system) {
1061                     (
1062                         AppendableValue::Css {
1063                             css,
1064                             with_variables,
1065                         },
1066                         _,
1067                     ) => {
1068                         debug_assert!(!css.is_empty());
1069                         AppendableValue::Css {
1070                             css: css,
1071                             with_variables: with_variables,
1072                         }
1073                     },
1074                     #[cfg(feature = "gecko")]
1075                     (_, Some(sys)) => {
1076                         sys.to_css(&mut CssWriter::new(&mut v))?;
1077                         AppendableValue::Css {
1078                             css: CssStringBorrow::from(&v),
1079                             with_variables: false,
1080                         }
1081                     },
1082                     (other, _) => {
1083                         append_declaration_value(&mut v, other)?;
1085                         // Substep 6
1086                         if v.is_empty() {
1087                             continue;
1088                         }
1090                         AppendableValue::Css {
1091                             css: CssStringBorrow::from(&v),
1092                             with_variables: false,
1093                         }
1094                     },
1095                 };
1097                 // Substeps 7 and 8
1098                 append_serialization::<Cloned<slice::Iter<_>>, _>(
1099                     dest,
1100                     &shorthand,
1101                     value,
1102                     importance,
1103                     &mut is_first_serialization,
1104                 )?;
1106                 for current_longhand in &current_longhands {
1107                     let longhand_id = match current_longhand.id() {
1108                         PropertyDeclarationId::Longhand(id) => id,
1109                         PropertyDeclarationId::Custom(..) => unreachable!(),
1110                     };
1112                     // Substep 9
1113                     already_serialized.insert(longhand_id.into());
1114                 }
1116                 // FIXME(https://github.com/w3c/csswg-drafts/issues/1774)
1117                 // The specification does not include an instruction to abort
1118                 // the shorthand loop at this point, but doing so both matches
1119                 // Gecko and makes sense since shorthands are checked in
1120                 // preferred order.
1121                 break;
1122             }
1124             // Step 3.3.4
1125             if already_serialized.contains(longhand_id.into()) {
1126                 continue;
1127             }
1129             // Steps 3.3.5, 3.3.6 & 3.3.7
1130             // Need to specify an iterator type here even though it’s unused to work around
1131             // "error: unable to infer enough type information about `_`;
1132             //  type annotations or generic parameter binding required [E0282]"
1133             // Use the same type as earlier call to reuse generated code.
1134             append_serialization::<Cloned<slice::Iter<_>>, _>(
1135                 dest,
1136                 &property,
1137                 AppendableValue::Declaration(declaration),
1138                 importance,
1139                 &mut is_first_serialization,
1140             )?;
1142             // Step 3.3.8
1143             already_serialized.insert(longhand_id.into());
1144         }
1146         // Step 4
1147         Ok(())
1148     }
1151 /// A convenient enum to represent different kinds of stuff that can represent a
1152 /// _value_ in the serialization of a property declaration.
1153 pub enum AppendableValue<'a, I>
1154 where
1155     I: Iterator<Item = &'a PropertyDeclaration>,
1157     /// A given declaration, of which we'll serialize just the value.
1158     Declaration(&'a PropertyDeclaration),
1159     /// A set of declarations for a given shorthand.
1160     ///
1161     /// FIXME: This needs more docs, where are the shorthands expanded? We print
1162     /// the property name before-hand, don't we?
1163     DeclarationsForShorthand(ShorthandId, I),
1164     /// A raw CSS string, coming for example from a property with CSS variables,
1165     /// or when storing a serialized shorthand value before appending directly.
1166     Css {
1167         /// The raw CSS string.
1168         css: CssStringBorrow<'a>,
1169         /// Whether the original serialization contained variables or not.
1170         with_variables: bool,
1171     },
1174 /// Potentially appends whitespace after the first (property: value;) pair.
1175 fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result
1176 where
1177     W: Write,
1179     if !*is_first_serialization {
1180         dest.write_str(" ")
1181     } else {
1182         *is_first_serialization = false;
1183         Ok(())
1184     }
1187 /// Append a given kind of appendable value to a serialization.
1188 pub fn append_declaration_value<'a, I>(
1189     dest: &mut CssStringWriter,
1190     appendable_value: AppendableValue<'a, I>,
1191 ) -> fmt::Result
1192 where
1193     I: Iterator<Item = &'a PropertyDeclaration>,
1195     match appendable_value {
1196         AppendableValue::Css { css, .. } => css.append_to(dest),
1197         AppendableValue::Declaration(decl) => decl.to_css(dest),
1198         AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
1199             shorthand.longhands_to_css(decls, &mut CssWriter::new(dest))
1200         },
1201     }
1204 /// Append a given property and value pair to a serialization.
1205 pub fn append_serialization<'a, I, N>(
1206     dest: &mut CssStringWriter,
1207     property_name: &N,
1208     appendable_value: AppendableValue<'a, I>,
1209     importance: Importance,
1210     is_first_serialization: &mut bool,
1211 ) -> fmt::Result
1212 where
1213     I: Iterator<Item = &'a PropertyDeclaration>,
1214     N: ToCss,
1216     handle_first_serialization(dest, is_first_serialization)?;
1218     property_name.to_css(&mut CssWriter::new(dest))?;
1219     dest.write_char(':')?;
1221     // for normal parsed values, add a space between key: and value
1222     match appendable_value {
1223         AppendableValue::Declaration(decl) => {
1224             if !decl.value_is_unparsed() {
1225                 // For normal parsed values, add a space between key: and value.
1226                 dest.write_str(" ")?
1227             }
1228         },
1229         AppendableValue::Css { with_variables, .. } => {
1230             if !with_variables {
1231                 dest.write_str(" ")?
1232             }
1233         },
1234         // Currently append_serialization is only called with a Css or
1235         // a Declaration AppendableValue.
1236         AppendableValue::DeclarationsForShorthand(..) => unreachable!(),
1237     }
1239     append_declaration_value(dest, appendable_value)?;
1241     if importance.important() {
1242         dest.write_str(" !important")?;
1243     }
1245     dest.write_char(';')
1248 /// A helper to parse the style attribute of an element, in order for this to be
1249 /// shared between Servo and Gecko.
1251 /// Inline because we call this cross-crate.
1252 #[inline]
1253 pub fn parse_style_attribute(
1254     input: &str,
1255     url_data: &UrlExtraData,
1256     error_reporter: Option<&dyn ParseErrorReporter>,
1257     quirks_mode: QuirksMode,
1258 ) -> PropertyDeclarationBlock {
1259     let context = ParserContext::new(
1260         Origin::Author,
1261         url_data,
1262         Some(CssRuleType::Style),
1263         ParsingMode::DEFAULT,
1264         quirks_mode,
1265         error_reporter,
1266         None,
1267     );
1269     let mut input = ParserInput::new(input);
1270     parse_property_declaration_list(&context, &mut Parser::new(&mut input), None)
1273 /// Parse a given property declaration. Can result in multiple
1274 /// `PropertyDeclaration`s when expanding a shorthand, for example.
1276 /// This does not attempt to parse !important at all.
1277 #[inline]
1278 pub fn parse_one_declaration_into(
1279     declarations: &mut SourcePropertyDeclaration,
1280     id: PropertyId,
1281     input: &str,
1282     url_data: &UrlExtraData,
1283     error_reporter: Option<&dyn ParseErrorReporter>,
1284     parsing_mode: ParsingMode,
1285     quirks_mode: QuirksMode,
1286 ) -> Result<(), ()> {
1287     let context = ParserContext::new(
1288         Origin::Author,
1289         url_data,
1290         Some(CssRuleType::Style),
1291         parsing_mode,
1292         quirks_mode,
1293         error_reporter,
1294         None,
1295     );
1297     let property_id_for_error_reporting = if context.error_reporting_enabled() {
1298         Some(id.clone())
1299     } else {
1300         None
1301     };
1303     let mut input = ParserInput::new(input);
1304     let mut parser = Parser::new(&mut input);
1305     let start_position = parser.position();
1306     parser
1307         .parse_entirely(|parser| {
1308             PropertyDeclaration::parse_into(declarations, id, &context, parser)
1309         })
1310         .map_err(|err| {
1311             if context.error_reporting_enabled() {
1312                 report_one_css_error(
1313                     &context,
1314                     None,
1315                     None,
1316                     err,
1317                     parser.slice_from(start_position),
1318                     property_id_for_error_reporting,
1319                 )
1320             }
1321         })
1324 /// A struct to parse property declarations.
1325 struct PropertyDeclarationParser<'a, 'b: 'a> {
1326     context: &'a ParserContext<'b>,
1327     declarations: &'a mut SourcePropertyDeclaration,
1328     /// The last parsed property id if any.
1329     last_parsed_property_id: Option<PropertyId>,
1332 /// Default methods reject all at rules.
1333 impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b> {
1334     type PreludeNoBlock = ();
1335     type PreludeBlock = ();
1336     type AtRule = Importance;
1337     type Error = StyleParseErrorKind<'i>;
1340 /// Based on NonMozillaVendorIdentifier from Gecko's CSS parser.
1341 fn is_non_mozilla_vendor_identifier(name: &str) -> bool {
1342     (name.starts_with("-") && !name.starts_with("-moz-")) || name.starts_with("_")
1345 impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
1346     type Declaration = Importance;
1347     type Error = StyleParseErrorKind<'i>;
1349     fn parse_value<'t>(
1350         &mut self,
1351         name: CowRcStr<'i>,
1352         input: &mut Parser<'i, 't>,
1353     ) -> Result<Importance, ParseError<'i>> {
1354         let id = match PropertyId::parse(&name, self.context) {
1355             Ok(id) => id,
1356             Err(..) => {
1357                 return Err(input.new_custom_error(StyleParseErrorKind::UnknownProperty(name)));
1358             },
1359         };
1360         if self.context.error_reporting_enabled() {
1361             self.last_parsed_property_id = Some(id.clone());
1362         }
1363         input.parse_until_before(Delimiter::Bang, |input| {
1364             PropertyDeclaration::parse_into(self.declarations, id, self.context, input)
1365         })?;
1366         let importance = match input.try(parse_important) {
1367             Ok(()) => Importance::Important,
1368             Err(_) => Importance::Normal,
1369         };
1370         // In case there is still unparsed text in the declaration, we should roll back.
1371         input.expect_exhausted()?;
1372         Ok(importance)
1373     }
1376 type SmallParseErrorVec<'i> = SmallVec<[(ParseError<'i>, &'i str, Option<PropertyId>); 2]>;
1378 fn alias_of_known_property(name: &str) -> Option<PropertyId> {
1379     let mut prefixed = String::with_capacity(name.len() + 5);
1380     prefixed.push_str("-moz-");
1381     prefixed.push_str(name);
1382     PropertyId::parse_enabled_for_all_content(&prefixed).ok()
1385 #[cold]
1386 fn report_one_css_error<'i>(
1387     context: &ParserContext,
1388     block: Option<&PropertyDeclarationBlock>,
1389     selectors: Option<&SelectorList<SelectorImpl>>,
1390     mut error: ParseError<'i>,
1391     slice: &str,
1392     property: Option<PropertyId>,
1393 ) {
1394     debug_assert!(context.error_reporting_enabled());
1396     fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool {
1397         match *property {
1398             PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => block.contains(id),
1399             PropertyId::ShorthandAlias(id, _) | PropertyId::Shorthand(id) => {
1400                 id.longhands().all(|longhand| block.contains(longhand))
1401             },
1402             // NOTE(emilio): We could do this, but it seems of limited utility,
1403             // and it's linear on the size of the declaration block, so let's
1404             // not.
1405             PropertyId::Custom(..) => false,
1406         }
1407     }
1409     if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty(ref name)) = error.kind {
1410         if is_non_mozilla_vendor_identifier(name) {
1411             // If the unrecognized property looks like a vendor-specific property,
1412             // silently ignore it instead of polluting the error output.
1413             return;
1414         }
1415         if let Some(alias) = alias_of_known_property(name) {
1416             // This is an unknown property, but its -moz-* version is known.
1417             // We don't want to report error if the -moz-* version is already
1418             // specified.
1419             if let Some(block) = block {
1420                 if all_properties_in_block(block, &alias) {
1421                     return;
1422                 }
1423             }
1424         }
1425     }
1427     if let Some(ref property) = property {
1428         if let Some(block) = block {
1429             if all_properties_in_block(block, property) {
1430                 return;
1431             }
1432         }
1433         error = match *property {
1434             PropertyId::Custom(ref c) => {
1435                 StyleParseErrorKind::new_invalid(format!("--{}", c), error)
1436             },
1437             _ => StyleParseErrorKind::new_invalid(property.non_custom_id().unwrap().name(), error),
1438         };
1439     }
1441     let location = error.location;
1442     let error = ContextualParseError::UnsupportedPropertyDeclaration(slice, error, selectors);
1443     context.log_css_error(location, error);
1446 #[cold]
1447 fn report_css_errors(
1448     context: &ParserContext,
1449     block: &PropertyDeclarationBlock,
1450     selectors: Option<&SelectorList<SelectorImpl>>,
1451     errors: &mut SmallParseErrorVec,
1452 ) {
1453     for (error, slice, property) in errors.drain(..) {
1454         report_one_css_error(context, Some(block), selectors, error, slice, property)
1455     }
1458 /// Parse a list of property declarations and return a property declaration
1459 /// block.
1460 pub fn parse_property_declaration_list(
1461     context: &ParserContext,
1462     input: &mut Parser,
1463     selectors: Option<&SelectorList<SelectorImpl>>,
1464 ) -> PropertyDeclarationBlock {
1465     let mut declarations = SourcePropertyDeclaration::new();
1466     let mut block = PropertyDeclarationBlock::new();
1467     let parser = PropertyDeclarationParser {
1468         context,
1469         last_parsed_property_id: None,
1470         declarations: &mut declarations,
1471     };
1472     let mut iter = DeclarationListParser::new(input, parser);
1473     let mut errors = SmallParseErrorVec::new();
1474     while let Some(declaration) = iter.next() {
1475         match declaration {
1476             Ok(importance) => {
1477                 block.extend(iter.parser.declarations.drain(), importance);
1478                 // We've successfully parsed a declaration, so forget about
1479                 // `last_parsed_property_id`. It'd be wrong to associate any
1480                 // following error with this property.
1481                 iter.parser.last_parsed_property_id = None;
1482             },
1483             Err((error, slice)) => {
1484                 iter.parser.declarations.clear();
1486                 if context.error_reporting_enabled() {
1487                     let property = iter.parser.last_parsed_property_id.take();
1488                     errors.push((error, slice, property));
1489                 }
1490             },
1491         }
1492     }
1494     if !errors.is_empty() {
1495         report_css_errors(context, &block, selectors, &mut errors)
1496     }
1498     block