1#![deny(missing_docs)]
8
9use super::{
10 property_counts, AllShorthand, ComputedValues, LogicalGroupSet, LonghandIdSet,
11 LonghandIdSetIterator, NonCustomPropertyId, NonCustomPropertyIdSet, PropertyDeclaration,
12 PropertyDeclarationId, PropertyId, ShorthandId, SourcePropertyDeclaration,
13 SourcePropertyDeclarationDrain, SubpropertiesVec,
14};
15
16use crate::context::{QuirksMode, TreeCountingCaches};
17use crate::custom_properties;
18use crate::derives::*;
19use crate::dom::{AttributeTracker, DummyElementContext};
20use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
21use crate::parser::ParserContext;
22use crate::properties::{
23 animated_properties::{AnimationValue, AnimationValueMap},
24 StyleBuilder,
25};
26use crate::rule_cache::RuleCacheConditions;
27use crate::rule_tree::RuleCascadeFlags;
28use crate::selector_map::PrecomputedHashSet;
29use crate::selector_parser::SelectorImpl;
30use crate::shared_lock::Locked;
31use crate::stylesheets::container_rule::ContainerSizeQuery;
32use crate::stylesheets::{CssRuleType, Origin, UrlExtraData};
33use crate::stylist::Stylist;
34use crate::typed_om::TypedValueList;
35use crate::values::computed::Context;
36use cssparser::{
37 parse_important, AtRuleParser, CowRcStr, DeclarationParser, Delimiter, ParseErrorKind, Parser,
38 ParserState, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation,
39};
40use itertools::Itertools;
41use selectors::SelectorList;
42use servo_arc::Arc;
43use smallbitvec::SmallBitVec;
44use smallvec::SmallVec;
45use std::borrow::Cow;
46use std::fmt::{self, Write};
47use std::iter::Zip;
48use std::slice::Iter;
49use std::sync::atomic::AtomicBool;
50use style_traits::{
51 CssString, CssStringWriter, CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss,
52};
53use thin_vec::ThinVec;
54
55#[derive(Default)]
57pub struct AnimationDeclarations {
58 pub animations: Option<Arc<Locked<PropertyDeclarationBlock>>>,
60 pub transitions: Option<Arc<Locked<PropertyDeclarationBlock>>>,
62}
63
64impl AnimationDeclarations {
65 pub fn is_empty(&self) -> bool {
67 self.animations.is_none() && self.transitions.is_none()
68 }
69}
70
71#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74enum DeclarationUpdate {
75 None,
77 Append,
79 UpdateInPlace { pos: usize },
81 AppendAndRemove { pos: usize },
84}
85
86#[derive(Default)]
89pub struct SourcePropertyDeclarationUpdate {
90 updates: SubpropertiesVec<DeclarationUpdate>,
91 new_count: usize,
92 any_removal: bool,
93}
94
95#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
99pub enum Importance {
100 Normal,
102
103 Important,
105}
106
107impl Default for Importance {
108 fn default() -> Self {
109 Self::Normal
110 }
111}
112
113impl Importance {
114 pub fn important(self) -> bool {
116 match self {
117 Self::Normal => false,
118 Self::Important => true,
119 }
120 }
121}
122
123#[derive(Clone, Debug, ToShmem, Default, MallocSizeOf)]
125pub struct PropertyDeclarationIdSet {
126 longhands: LonghandIdSet,
127 custom: PrecomputedHashSet<custom_properties::Name>,
128}
129
130impl PropertyDeclarationIdSet {
131 pub fn insert(&mut self, id: PropertyDeclarationId) -> bool {
133 match id {
134 PropertyDeclarationId::Longhand(id) => {
135 if self.longhands.contains(id) {
136 return false;
137 }
138 self.longhands.insert(id);
139 true
140 },
141 PropertyDeclarationId::Custom(name) => self.custom.insert((*name).clone()),
142 }
143 }
144
145 pub fn contains(&self, id: PropertyDeclarationId) -> bool {
147 match id {
148 PropertyDeclarationId::Longhand(id) => self.longhands.contains(id),
149 PropertyDeclarationId::Custom(name) => self.custom.contains(name),
150 }
151 }
152
153 pub fn remove(&mut self, id: PropertyDeclarationId) {
155 match id {
156 PropertyDeclarationId::Longhand(id) => self.longhands.remove(id),
157 PropertyDeclarationId::Custom(name) => {
158 self.custom.remove(name);
159 },
160 }
161 }
162
163 pub fn clear(&mut self) {
165 self.longhands.clear();
166 self.custom.clear();
167 }
168
169 #[inline]
171 pub fn is_empty(&self) -> bool {
172 self.longhands.is_empty() && self.custom.is_empty()
173 }
174 #[inline]
176 pub fn contains_any_reset(&self) -> bool {
177 self.longhands.contains_any_reset()
178 }
179
180 #[inline]
182 pub fn contains_all_longhands(&self, longhands: &LonghandIdSet) -> bool {
183 self.longhands.contains_all(longhands)
184 }
185
186 #[inline]
188 pub fn contains_all(&self, properties: &PropertyDeclarationIdSet) -> bool {
189 if !self.longhands.contains_all(&properties.longhands) {
190 return false;
191 }
192 if properties.custom.len() > self.custom.len() {
193 return false;
194 }
195 properties
196 .custom
197 .iter()
198 .all(|item| self.custom.contains(item))
199 }
200
201 pub fn iter(&self) -> PropertyDeclarationIdSetIterator<'_> {
203 PropertyDeclarationIdSetIterator {
204 longhands: self.longhands.iter(),
205 custom: self.custom.iter(),
206 }
207 }
208}
209
210pub struct PropertyDeclarationIdSetIterator<'a> {
212 longhands: LonghandIdSetIterator<'a>,
213 custom: std::collections::hash_set::Iter<'a, custom_properties::Name>,
214}
215
216impl<'a> Iterator for PropertyDeclarationIdSetIterator<'a> {
217 type Item = PropertyDeclarationId<'a>;
218
219 fn next(&mut self) -> Option<Self::Item> {
220 match self.longhands.next() {
224 Some(id) => Some(PropertyDeclarationId::Longhand(id)),
225 None => self.custom.next().map(PropertyDeclarationId::Custom),
226 }
227 }
228}
229
230#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
232#[derive(Default)]
233pub struct PropertyDeclarationBlock {
234 declarations: ThinVec<PropertyDeclaration>,
238
239 declarations_importance: SmallBitVec,
241
242 property_ids: PropertyDeclarationIdSet,
244
245 pub immutable: AtomicBool,
249}
250
251impl to_shmem::ToShmem for PropertyDeclarationBlock {
252 fn to_shmem(&self, builder: &mut to_shmem::SharedMemoryBuilder) -> to_shmem::Result<Self> {
253 use std::mem::ManuallyDrop;
254 let declarations = self.declarations.to_shmem(builder)?;
255 let declarations_importance = self.declarations_importance.to_shmem(builder)?;
256 let property_ids = self.property_ids.to_shmem(builder)?;
257 let immutable = AtomicBool::new(true);
258
259 Ok(ManuallyDrop::new(Self {
260 declarations: ManuallyDrop::into_inner(declarations),
261 declarations_importance: ManuallyDrop::into_inner(declarations_importance),
262 property_ids: ManuallyDrop::into_inner(property_ids),
263 immutable,
264 }))
265 }
266}
267
268impl Clone for PropertyDeclarationBlock {
269 fn clone(&self) -> Self {
270 Self {
271 declarations: self.declarations.clone(),
272 declarations_importance: self.declarations_importance.clone(),
273 property_ids: self.property_ids.clone(),
274 immutable: AtomicBool::new(false),
275 }
276 }
277}
278
279impl PartialEq for PropertyDeclarationBlock {
280 fn eq(&self, other: &Self) -> bool {
281 self.declarations == other.declarations
285 && self.declarations_importance == other.declarations_importance
286 }
287}
288
289pub struct DeclarationImportanceIterator<'a> {
291 iter: Zip<Iter<'a, PropertyDeclaration>, smallbitvec::Iter<'a>>,
292}
293
294impl<'a> Default for DeclarationImportanceIterator<'a> {
295 fn default() -> Self {
296 Self {
297 iter: [].iter().zip(smallbitvec::Iter::default()),
298 }
299 }
300}
301
302impl<'a> DeclarationImportanceIterator<'a> {
303 fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
305 DeclarationImportanceIterator {
306 iter: declarations.iter().zip(important.iter()),
307 }
308 }
309}
310
311impl<'a> Iterator for DeclarationImportanceIterator<'a> {
312 type Item = (&'a PropertyDeclaration, Importance);
313
314 #[inline]
315 fn next(&mut self) -> Option<Self::Item> {
316 self.iter.next().map(|(decl, important)| {
317 (
318 decl,
319 if important {
320 Importance::Important
321 } else {
322 Importance::Normal
323 },
324 )
325 })
326 }
327
328 #[inline]
329 fn size_hint(&self) -> (usize, Option<usize>) {
330 self.iter.size_hint()
331 }
332}
333
334impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
335 #[inline(always)]
336 fn next_back(&mut self) -> Option<Self::Item> {
337 self.iter.next_back().map(|(decl, important)| {
338 (
339 decl,
340 if important {
341 Importance::Important
342 } else {
343 Importance::Normal
344 },
345 )
346 })
347 }
348}
349
350pub struct AnimationValueIterator<'a, 'cx, 'cx_a: 'cx> {
352 iter: DeclarationImportanceIterator<'a>,
353 context: &'cx mut Context<'cx_a>,
354 style: &'a ComputedValues,
355 default_values: &'a ComputedValues,
356}
357
358impl<'a, 'cx, 'cx_a: 'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
359 fn new(
360 declarations: &'a PropertyDeclarationBlock,
361 context: &'cx mut Context<'cx_a>,
362 style: &'a ComputedValues,
363 default_values: &'a ComputedValues,
364 ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
365 AnimationValueIterator {
366 iter: declarations.declaration_importance_iter(),
367 context,
368 style,
369 default_values,
370 }
371 }
372}
373
374impl<'a, 'cx, 'cx_a: 'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
375 type Item = AnimationValue;
376 #[inline]
377 fn next(&mut self) -> Option<Self::Item> {
378 loop {
379 let (decl, importance) = self.iter.next()?;
380
381 if importance.important() {
382 continue;
383 }
384
385 let animation = AnimationValue::from_declaration(
386 decl,
387 self.context,
388 self.style,
389 self.default_values,
390 &mut AttributeTracker::new_dummy(),
392 );
393
394 if let Some(anim) = animation {
395 return Some(anim);
396 }
397 }
398 }
399}
400
401impl fmt::Debug for PropertyDeclarationBlock {
402 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
403 self.declarations.fmt(f)
404 }
405}
406
407impl PropertyDeclarationBlock {
408 #[inline]
410 pub fn len(&self) -> usize {
411 self.declarations.len()
412 }
413
414 #[inline]
416 pub fn is_empty(&self) -> bool {
417 self.declarations.is_empty()
418 }
419
420 #[inline]
422 pub fn new() -> Self {
423 PropertyDeclarationBlock {
424 declarations: ThinVec::new(),
425 declarations_importance: SmallBitVec::new(),
426 property_ids: PropertyDeclarationIdSet::default(),
427 immutable: AtomicBool::new(false),
428 }
429 }
430
431 pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
433 let mut property_ids = PropertyDeclarationIdSet::default();
434 property_ids.insert(declaration.id());
435 let mut declarations = ThinVec::with_capacity(1);
436 declarations.push(declaration);
437 PropertyDeclarationBlock {
438 declarations,
439 declarations_importance: SmallBitVec::from_elem(1, importance.important()),
440 property_ids,
441 immutable: AtomicBool::new(false),
442 }
443 }
444
445 #[inline]
447 pub fn declarations(&self) -> &[PropertyDeclaration] {
448 &self.declarations
449 }
450
451 #[inline]
453 pub fn declarations_importance(&self) -> &SmallBitVec {
454 &self.declarations_importance
455 }
456
457 #[inline]
459 pub fn declaration_importance_iter(&self) -> DeclarationImportanceIterator<'_> {
460 DeclarationImportanceIterator::new(&self.declarations, &self.declarations_importance)
461 }
462
463 #[inline]
465 pub fn normal_declaration_iter(&self) -> impl DoubleEndedIterator<Item = &PropertyDeclaration> {
466 self.declaration_importance_iter()
467 .filter(|(_, importance)| !importance.important())
468 .map(|(declaration, _)| declaration)
469 }
470
471 #[inline]
473 pub fn to_animation_value_iter<'a, 'cx, 'cx_a: 'cx>(
474 &'a self,
475 context: &'cx mut Context<'cx_a>,
476 style: &'a ComputedValues,
477 default_values: &'a ComputedValues,
478 ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
479 AnimationValueIterator::new(self, context, style, default_values)
480 }
481
482 #[inline]
487 pub fn any_important(&self) -> bool {
488 !self.declarations_importance.all_false()
489 }
490
491 #[inline]
496 pub fn any_normal(&self) -> bool {
497 !self.declarations_importance.all_true()
498 }
499
500 #[inline]
503 pub fn property_ids(&self) -> &PropertyDeclarationIdSet {
504 &self.property_ids
505 }
506
507 #[inline]
509 pub fn contains(&self, id: PropertyDeclarationId) -> bool {
510 self.property_ids.contains(id)
511 }
512
513 #[inline]
515 pub fn contains_any_reset(&self) -> bool {
516 self.property_ids.contains_any_reset()
517 }
518
519 #[inline]
524 pub fn get(
525 &self,
526 property: PropertyDeclarationId,
527 ) -> Option<(&PropertyDeclaration, Importance)> {
528 if !self.contains(property) {
529 return None;
530 }
531 self.declaration_importance_iter()
532 .find(|(declaration, _)| declaration.id() == property)
533 }
534
535 pub fn shorthand_to_css(
538 &self,
539 shorthand: ShorthandId,
540 dest: &mut CssStringWriter,
541 ) -> fmt::Result {
542 let mut list = SmallVec::<[&_; 10]>::new();
545 let mut important_count = 0;
546
547 for longhand in shorthand.longhands() {
549 let declaration = self.get(PropertyDeclarationId::Longhand(longhand));
551
552 match declaration {
554 Some((declaration, importance)) => {
555 list.push(declaration);
556 if importance.important() {
557 important_count += 1;
558 }
559 },
560 None => return Ok(()),
561 }
562 }
563
564 if important_count > 0 && important_count != list.len() {
567 return Ok(());
568 }
569
570 match shorthand.get_shorthand_appendable_value(&list) {
574 Some(appendable_value) => append_declaration_value(dest, appendable_value),
575 None => Ok(()),
576 }
577 }
578
579 pub fn property_value_to_css(
583 &self,
584 property: &PropertyId,
585 dest: &mut CssStringWriter,
586 ) -> fmt::Result {
587 let longhand_or_custom = match property.as_shorthand() {
591 Ok(shorthand) => return self.shorthand_to_css(shorthand, dest),
592 Err(longhand_or_custom) => longhand_or_custom,
593 };
594
595 if let Some((value, _importance)) = self.get(longhand_or_custom) {
596 value.to_css(dest)
598 } else {
599 Ok(())
601 }
602 }
603
604 pub fn property_priority(&self, property: &PropertyId) -> Importance {
606 match property.as_shorthand() {
610 Ok(shorthand) => {
611 if shorthand.longhands().all(|l| {
613 self.get(PropertyDeclarationId::Longhand(l))
614 .is_some_and(|(_, importance)| importance.important())
615 }) {
616 Importance::Important
617 } else {
618 Importance::Normal
619 }
620 },
621 Err(longhand_or_custom) => {
622 self.get(longhand_or_custom)
624 .map_or(Importance::Normal, |(_, importance)| importance)
625 },
626 }
627 }
628
629 pub fn property_value_to_typed_value_list(
633 &self,
634 property: &PropertyId,
635 ) -> Result<Option<TypedValueList>, ()> {
636 match property.as_shorthand() {
637 Ok(shorthand) => {
638 if shorthand
639 .longhands()
640 .all(|longhand| self.contains(PropertyDeclarationId::Longhand(longhand)))
641 {
642 Ok(None)
643 } else {
644 Err(())
645 }
646 },
647 Err(longhand_or_custom) => match self.get(longhand_or_custom) {
648 Some((value, _importance)) => Ok(value.to_typed_value_list()),
649 None => Err(()),
650 },
651 }
652 }
653
654 pub fn extend(
659 &mut self,
660 mut drain: SourcePropertyDeclarationDrain,
661 importance: Importance,
662 ) -> bool {
663 let all_shorthand_len = match drain.all_shorthand {
664 AllShorthand::NotSet => 0,
665 AllShorthand::CSSWideKeyword(_) | AllShorthand::WithVariables(_) => {
666 property_counts::ALL_SHORTHAND_EXPANDED
667 },
668 };
669 let push_calls_count = drain.declarations.len() + all_shorthand_len;
670
671 self.declarations.reserve(push_calls_count);
673
674 let mut changed = false;
675 for decl in &mut drain.declarations {
676 changed |= self.push(decl, importance);
677 }
678 drain
679 .all_shorthand
680 .declarations()
681 .fold(changed, |changed, decl| {
682 changed | self.push(decl, importance)
683 })
684 }
685
686 pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) -> bool {
692 let id = declaration.id();
693 if !self.property_ids.insert(id) {
694 let mut index_to_remove = None;
695 for (i, slot) in self.declarations.iter_mut().enumerate() {
696 if slot.id() != id {
697 continue;
698 }
699
700 let important = self.declarations_importance[i];
701
702 if important && !importance.important() {
705 return false;
706 }
707
708 index_to_remove = Some(i);
709 break;
710 }
711
712 if let Some(index) = index_to_remove {
713 self.declarations.remove(index);
714 self.declarations_importance.remove(index);
715 self.declarations.push(declaration);
716 self.declarations_importance.push(importance.important());
717 return true;
718 }
719 }
720
721 self.declarations.push(declaration);
722 self.declarations_importance.push(importance.important());
723 true
724 }
725
726 pub fn prepare_for_update(
730 &self,
731 source_declarations: &SourcePropertyDeclaration,
732 importance: Importance,
733 updates: &mut SourcePropertyDeclarationUpdate,
734 ) -> bool {
735 debug_assert!(updates.updates.is_empty());
736 if !matches!(source_declarations.all_shorthand, AllShorthand::NotSet) {
738 debug_assert!(source_declarations.declarations.is_empty());
739 return source_declarations
740 .all_shorthand
741 .declarations()
742 .any(|decl| {
743 !self.contains(decl.id())
744 || self
745 .declarations
746 .iter()
747 .enumerate()
748 .find(|&(_, d)| d.id() == decl.id())
749 .is_none_or(|(i, d)| {
750 let important = self.declarations_importance[i];
751 *d != decl || important != importance.important()
752 })
753 });
754 }
755 let mut any_update = false;
757 let new_count = &mut updates.new_count;
758 let any_removal = &mut updates.any_removal;
759 let updates = &mut updates.updates;
760 updates.extend(
761 source_declarations
762 .declarations
763 .iter()
764 .map(|declaration| {
765 if !self.contains(declaration.id()) {
766 return DeclarationUpdate::Append;
767 }
768 let longhand_id = declaration.id().as_longhand();
769 if let Some(longhand_id) = longhand_id {
770 if let Some(logical_group) = longhand_id.logical_group() {
771 let mut needs_append = false;
772 for (pos, decl) in self.declarations.iter().enumerate().rev() {
773 let id = match decl.id().as_longhand() {
774 Some(id) => id,
775 None => continue,
776 };
777 if id == longhand_id {
778 if needs_append {
779 return DeclarationUpdate::AppendAndRemove { pos };
780 }
781 let important = self.declarations_importance[pos];
782 if decl == declaration && important == importance.important() {
783 return DeclarationUpdate::None;
784 }
785 return DeclarationUpdate::UpdateInPlace { pos };
786 }
787 if !needs_append
788 && id.logical_group() == Some(logical_group)
789 && id.is_logical() != longhand_id.is_logical()
790 {
791 needs_append = true;
792 }
793 }
794 unreachable!("Longhand should be found in loop above");
795 }
796 }
797 self.declarations
798 .iter()
799 .enumerate()
800 .find(|&(_, decl)| decl.id() == declaration.id())
801 .map_or(DeclarationUpdate::Append, |(pos, decl)| {
802 let important = self.declarations_importance[pos];
803 if decl == declaration && important == importance.important() {
804 DeclarationUpdate::None
805 } else {
806 DeclarationUpdate::UpdateInPlace { pos }
807 }
808 })
809 })
810 .inspect(|update| {
811 if matches!(update, DeclarationUpdate::None) {
812 return;
813 }
814 any_update = true;
815 match update {
816 DeclarationUpdate::Append => {
817 *new_count += 1;
818 },
819 DeclarationUpdate::AppendAndRemove { .. } => {
820 *any_removal = true;
821 },
822 _ => {},
823 }
824 }),
825 );
826 any_update
827 }
828
829 pub fn update(
831 &mut self,
832 drain: SourcePropertyDeclarationDrain,
833 importance: Importance,
834 updates: &mut SourcePropertyDeclarationUpdate,
835 ) {
836 let important = importance.important();
837 if !matches!(drain.all_shorthand, AllShorthand::NotSet) {
838 debug_assert!(updates.updates.is_empty());
839 for decl in drain.all_shorthand.declarations() {
840 let id = decl.id();
841 if self.property_ids.insert(id) {
842 self.declarations.push(decl);
843 self.declarations_importance.push(important);
844 } else {
845 let (idx, slot) = self
846 .declarations
847 .iter_mut()
848 .enumerate()
849 .find(|(_, d)| d.id() == decl.id())
850 .unwrap();
851 *slot = decl;
852 self.declarations_importance.set(idx, important);
853 }
854 }
855 return;
856 }
857
858 self.declarations.reserve(updates.new_count);
859 if updates.any_removal {
860 struct UpdateOrRemoval<'a> {
862 item: &'a mut DeclarationUpdate,
863 pos: usize,
864 remove: bool,
865 }
866 let mut updates_and_removals: SubpropertiesVec<UpdateOrRemoval> = updates
867 .updates
868 .iter_mut()
869 .filter_map(|item| {
870 let (pos, remove) = match *item {
871 DeclarationUpdate::UpdateInPlace { pos } => (pos, false),
872 DeclarationUpdate::AppendAndRemove { pos } => (pos, true),
873 _ => return None,
874 };
875 Some(UpdateOrRemoval { item, pos, remove })
876 })
877 .collect();
878 updates_and_removals.sort_unstable_by_key(|update| update.pos);
881 updates_and_removals
882 .iter()
883 .rev()
884 .filter(|update| update.remove)
885 .for_each(|update| {
886 self.declarations.remove(update.pos);
887 self.declarations_importance.remove(update.pos);
888 });
889 let mut removed_count = 0;
891 for update in updates_and_removals.iter_mut() {
892 if update.remove {
893 removed_count += 1;
894 continue;
895 }
896 debug_assert_eq!(
897 *update.item,
898 DeclarationUpdate::UpdateInPlace { pos: update.pos }
899 );
900 *update.item = DeclarationUpdate::UpdateInPlace {
901 pos: update.pos - removed_count,
902 };
903 }
904 }
905 for (decl, update) in drain.declarations.zip_eq(updates.updates.iter()) {
907 match *update {
908 DeclarationUpdate::None => {},
909 DeclarationUpdate::Append | DeclarationUpdate::AppendAndRemove { .. } => {
910 self.property_ids.insert(decl.id());
911 self.declarations.push(decl);
912 self.declarations_importance.push(important);
913 },
914 DeclarationUpdate::UpdateInPlace { pos } => {
915 self.declarations[pos] = decl;
916 self.declarations_importance.set(pos, important);
917 },
918 }
919 }
920 updates.updates.clear();
921 }
922
923 #[inline]
926 pub fn first_declaration_to_remove(&self, property: &PropertyId) -> Option<usize> {
927 if let Err(longhand_or_custom) = property.as_shorthand() {
928 if !self.contains(longhand_or_custom) {
929 return None;
930 }
931 }
932
933 self.declarations
934 .iter()
935 .position(|declaration| declaration.id().is_or_is_longhand_of(property))
936 }
937
938 #[inline]
940 fn remove_declaration_at(&mut self, i: usize) {
941 self.property_ids.remove(self.declarations[i].id());
942 self.declarations_importance.remove(i);
943 self.declarations.remove(i);
944 }
945
946 #[inline]
948 pub fn clear(&mut self) {
949 self.declarations_importance.clear();
950 self.declarations.clear();
951 self.property_ids.clear();
952 }
953
954 #[inline]
959 pub fn remove_property(&mut self, property: &PropertyId, first_declaration: usize) {
960 debug_assert_eq!(
961 Some(first_declaration),
962 self.first_declaration_to_remove(property)
963 );
964 debug_assert!(self.declarations[first_declaration]
965 .id()
966 .is_or_is_longhand_of(property));
967
968 self.remove_declaration_at(first_declaration);
969
970 let shorthand = match property.as_shorthand() {
971 Ok(s) => s,
972 Err(_longhand_or_custom) => return,
973 };
974
975 let mut i = first_declaration;
976 let mut len = self.len();
977 while i < len {
978 if !self.declarations[i].id().is_longhand_of(shorthand) {
979 i += 1;
980 continue;
981 }
982
983 self.remove_declaration_at(i);
984 len -= 1;
985 }
986 }
987
988 pub fn single_value_to_css(
990 &self,
991 property: &PropertyId,
992 dest: &mut CssStringWriter,
993 computed_values: Option<&ComputedValues>,
994 stylist: &Stylist,
995 ) -> fmt::Result {
996 if let Ok(shorthand) = property.as_shorthand() {
997 return self.shorthand_to_css(shorthand, dest);
998 }
999
1000 let declaration = match self.declarations.first() {
1003 Some(d) => d,
1004 None => return Err(fmt::Error),
1005 };
1006
1007 let mut rule_cache_conditions = RuleCacheConditions::default();
1008 let mut tree_counting_caches = TreeCountingCaches::default();
1009 let mut context = Context::new(
1010 StyleBuilder::new(
1011 stylist.device(),
1012 Some(stylist),
1013 computed_values,
1014 None,
1015 None,
1016 false,
1017 ),
1018 stylist.quirks_mode(),
1019 &mut rule_cache_conditions,
1020 ContainerSizeQuery::none(),
1021 RuleCascadeFlags::empty(),
1022 &DummyElementContext {},
1023 &mut tree_counting_caches,
1024 );
1025
1026 if let Some(cv) = computed_values {
1027 context.builder.substitution_functions.custom_properties =
1028 cv.custom_properties().clone();
1029 };
1030
1031 match (declaration, computed_values) {
1032 (PropertyDeclaration::WithVariables(declaration), Some(_)) => declaration
1040 .value
1041 .substitute_variables(
1042 declaration.id,
1043 &context.builder.substitution_functions,
1044 stylist,
1045 &context,
1046 &mut Default::default(),
1047 &mut AttributeTracker::new_dummy(),
1048 )
1049 .to_css(dest),
1050 (d, _) => d.to_css(dest),
1051 }
1052 }
1053
1054 pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self {
1056 let len = animation_value_map.len();
1057 let mut declarations = ThinVec::with_capacity(len);
1058 let mut property_ids = PropertyDeclarationIdSet::default();
1059
1060 for (property, animation_value) in animation_value_map.iter() {
1061 property_ids.insert(property.as_borrowed());
1062 declarations.push(animation_value.uncompute());
1063 }
1064
1065 PropertyDeclarationBlock {
1066 declarations,
1067 property_ids,
1068 declarations_importance: SmallBitVec::from_elem(len, false),
1069 immutable: AtomicBool::new(false),
1070 }
1071 }
1072
1073 pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
1076 if let Err(longhand_or_custom) = property.as_shorthand() {
1077 if !self.property_ids.contains(longhand_or_custom) {
1078 return false;
1079 }
1080 }
1081 self.declarations.iter().any(|decl| {
1082 decl.id().is_or_is_longhand_of(property) && decl.get_css_wide_keyword().is_some()
1083 })
1084 }
1085
1086 pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
1092 let mut is_first_serialization = true; let mut already_serialized = NonCustomPropertyIdSet::new();
1104
1105 'declaration_loop: for (declaration, importance) in self.declaration_importance_iter() {
1107 let property = declaration.id();
1109 let longhand_id = match property {
1110 PropertyDeclarationId::Longhand(id) => id,
1111 PropertyDeclarationId::Custom(..) => {
1112 append_serialization(
1117 dest,
1118 &property,
1119 AppendableValue::Declaration(declaration),
1120 importance,
1121 &mut is_first_serialization,
1122 )?;
1123 continue;
1124 },
1125 };
1126
1127 if already_serialized.contains(longhand_id.into()) {
1129 continue;
1130 }
1131
1132 for shorthand in longhand_id.shorthands() {
1134 if already_serialized.contains(shorthand.into()) {
1136 continue;
1137 }
1138 already_serialized.insert(shorthand.into());
1139
1140 if shorthand.is_legacy_shorthand()
1141 && !(shorthand.allows_disabled_subproperties()
1142 && !NonCustomPropertyId::from(longhand_id).enabled_for_all_content())
1143 {
1144 continue;
1146 }
1147
1148 let longhands = {
1155 let mut ids = LonghandIdSet::new();
1158 for longhand in shorthand.longhands() {
1159 ids.insert(longhand);
1160 }
1161 ids
1162 };
1163
1164 if !self.property_ids.contains_all_longhands(&longhands) {
1169 continue;
1170 }
1171
1172 let mut current_longhands = SmallVec::<[&_; 10]>::new();
1175 let mut logical_groups = LogicalGroupSet::new();
1176 let mut saw_one = false;
1177 let mut logical_mismatch = false;
1178 let mut seen = LonghandIdSet::new();
1179 let mut important_count = 0;
1180
1181 for (declaration, importance) in self.declaration_importance_iter() {
1185 let longhand = match declaration.id() {
1186 PropertyDeclarationId::Longhand(id) => id,
1187 PropertyDeclarationId::Custom(..) => continue,
1188 };
1189
1190 if longhands.contains(longhand) {
1191 saw_one = true;
1192 if importance.important() {
1193 important_count += 1;
1194 }
1195 current_longhands.push(declaration);
1196 if shorthand != ShorthandId::All {
1197 if let Some(g) = longhand.logical_group() {
1200 logical_groups.insert(g);
1201 }
1202 seen.insert(longhand);
1203 if seen == longhands {
1204 break;
1205 }
1206 }
1207 } else if saw_one {
1208 if let Some(g) = longhand.logical_group() {
1209 if logical_groups.contains(g) {
1210 logical_mismatch = true;
1211 break;
1212 }
1213 }
1214 }
1215 }
1216
1217 let is_important = important_count > 0;
1223 if is_important && important_count != current_longhands.len() {
1224 continue;
1225 }
1226
1227 if logical_mismatch {
1235 continue;
1236 }
1237
1238 let importance = if is_important {
1239 Importance::Important
1240 } else {
1241 Importance::Normal
1242 };
1243
1244 let appendable_value =
1248 match shorthand.get_shorthand_appendable_value(¤t_longhands) {
1249 None => continue,
1250 Some(appendable_value) => appendable_value,
1251 };
1252
1253 let mut v = CssString::new();
1256 let value = match appendable_value {
1257 AppendableValue::Css(css) => {
1258 debug_assert!(!css.is_empty());
1259 appendable_value
1260 },
1261 other => {
1262 append_declaration_value(&mut v, other)?;
1263
1264 if v.is_empty() {
1268 continue;
1269 }
1270
1271 AppendableValue::Css({
1272 #[cfg(feature = "gecko")]
1274 unsafe {
1275 v.as_str_unchecked()
1276 }
1277 #[cfg(feature = "servo")]
1278 &v
1279 })
1280 },
1281 };
1282
1283 append_serialization(
1293 dest,
1294 &shorthand,
1295 value,
1296 importance,
1297 &mut is_first_serialization,
1298 )?;
1299
1300 for current_longhand in ¤t_longhands {
1304 let longhand_id = match current_longhand.id() {
1305 PropertyDeclarationId::Longhand(id) => id,
1306 PropertyDeclarationId::Custom(..) => unreachable!(),
1307 };
1308
1309 already_serialized.insert(longhand_id.into());
1311 }
1312
1313 continue 'declaration_loop;
1316 }
1317
1318 append_serialization(
1329 dest,
1330 &property,
1331 AppendableValue::Declaration(declaration),
1332 importance,
1333 &mut is_first_serialization,
1334 )?;
1335
1336 already_serialized.insert(longhand_id.into());
1339 }
1340
1341 Ok(())
1343 }
1344}
1345
1346pub enum AppendableValue<'a, 'b: 'a> {
1349 Declaration(&'a PropertyDeclaration),
1351 DeclarationsForShorthand(ShorthandId, &'a [&'b PropertyDeclaration]),
1356 Css(&'a str),
1359}
1360
1361fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result
1363where
1364 W: Write,
1365{
1366 if !*is_first_serialization {
1367 dest.write_char(' ')
1368 } else {
1369 *is_first_serialization = false;
1370 Ok(())
1371 }
1372}
1373
1374pub fn append_declaration_value<'a, 'b: 'a>(
1376 dest: &mut CssStringWriter,
1377 appendable_value: AppendableValue<'a, 'b>,
1378) -> fmt::Result {
1379 match appendable_value {
1380 AppendableValue::Css(css) => dest.write_str(css),
1381 AppendableValue::Declaration(decl) => decl.to_css(dest),
1382 AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
1383 shorthand.longhands_to_css(decls, dest)
1384 },
1385 }
1386}
1387
1388pub fn append_serialization<'a, 'b: 'a, N>(
1390 dest: &mut CssStringWriter,
1391 property_name: &N,
1392 appendable_value: AppendableValue<'a, 'b>,
1393 importance: Importance,
1394 is_first_serialization: &mut bool,
1395) -> fmt::Result
1396where
1397 N: ToCss,
1398{
1399 handle_first_serialization(dest, is_first_serialization)?;
1400
1401 property_name.to_css(&mut CssWriter::new(dest))?;
1402 dest.write_str(": ")?;
1403
1404 append_declaration_value(dest, appendable_value)?;
1405
1406 if importance.important() {
1407 dest.write_str(" !important")?;
1408 }
1409
1410 dest.write_char(';')
1411}
1412
1413#[inline]
1418pub fn parse_style_attribute(
1419 input: &str,
1420 url_data: &UrlExtraData,
1421 error_reporter: Option<&dyn ParseErrorReporter>,
1422 quirks_mode: QuirksMode,
1423 rule_type: CssRuleType,
1424) -> PropertyDeclarationBlock {
1425 let context = ParserContext::new(
1426 Origin::Author,
1427 url_data,
1428 Some(rule_type),
1429 ParsingMode::DEFAULT,
1430 quirks_mode,
1431 Default::default(),
1432 error_reporter,
1433 None,
1434 Default::default(),
1435 );
1436
1437 parse_property_declaration_list(&context, &mut Parser::new(input), &[])
1438}
1439
1440#[inline]
1445pub fn parse_one_declaration_into(
1446 declarations: &mut SourcePropertyDeclaration,
1447 id: PropertyId,
1448 input: &str,
1449 origin: Origin,
1450 url_data: &UrlExtraData,
1451 error_reporter: Option<&dyn ParseErrorReporter>,
1452 parsing_mode: ParsingMode,
1453 quirks_mode: QuirksMode,
1454 rule_type: CssRuleType,
1455) -> Result<(), ()> {
1456 let context = ParserContext::new(
1457 origin,
1458 url_data,
1459 Some(rule_type),
1460 parsing_mode,
1461 quirks_mode,
1462 Default::default(),
1463 error_reporter,
1464 None,
1465 Default::default(),
1466 );
1467
1468 let property_id_for_error_reporting = if context.error_reporting_enabled() {
1469 Some(id.clone())
1470 } else {
1471 None
1472 };
1473
1474 let mut parser = Parser::new(input);
1475 let start_position = parser.position();
1476 let start_location = parser.current_source_location();
1477 parser
1478 .parse_entirely(|parser| {
1479 PropertyDeclaration::parse_into(declarations, id, &context, parser)
1480 })
1481 .map_err(|err| {
1482 if context.error_reporting_enabled() {
1483 report_one_css_error(
1484 &context,
1485 None,
1486 &[],
1487 err,
1488 parser.slice_from(start_position),
1489 start_location,
1490 property_id_for_error_reporting,
1491 )
1492 }
1493 })
1494}
1495
1496struct PropertyDeclarationParser<'a, 'b: 'a, 'i> {
1498 context: &'a ParserContext<'b>,
1499 state: &'a mut DeclarationParserState<'i>,
1500}
1501
1502#[derive(Default)]
1506pub struct DeclarationParserState<'i> {
1507 output_block: PropertyDeclarationBlock,
1509 declarations: SourcePropertyDeclaration,
1512 importance: Importance,
1514 errors: SmallParseErrorVec<'i>,
1516 first_declaration_start: SourceLocation,
1518 last_parsed_property_id: Option<PropertyId>,
1520}
1521
1522impl<'i> DeclarationParserState<'i> {
1523 pub fn first_declaration_start(&self) -> SourceLocation {
1525 self.first_declaration_start
1526 }
1527
1528 pub fn has_parsed_declarations(&self) -> bool {
1530 !self.output_block.is_empty()
1531 }
1532
1533 pub fn take_declarations(&mut self) -> PropertyDeclarationBlock {
1535 std::mem::take(&mut self.output_block)
1536 }
1537
1538 pub fn parse_value(
1540 &mut self,
1541 context: &ParserContext,
1542 name: CowRcStr<'i>,
1543 input: &mut Parser<'i>,
1544 declaration_start: &ParserState,
1545 ) -> Result<(), ParseError> {
1546 let id = match PropertyId::parse(&name, context) {
1547 Ok(id) => id,
1548 Err(..) => {
1549 return Err(ParseError::custom(StyleParseErrorKind::UnknownProperty));
1550 },
1551 };
1552 if context.error_reporting_enabled() {
1553 self.last_parsed_property_id = Some(id.clone());
1554 }
1555 input.parse_until_before(Delimiter::Bang, |input| {
1556 PropertyDeclaration::parse_into(&mut self.declarations, id, context, input)
1557 })?;
1558 self.importance = match input.try_parse(parse_important) {
1559 Ok(()) => {
1560 if !context.allows_important_declarations() {
1561 return Err(ParseError::custom(
1562 StyleParseErrorKind::UnexpectedImportantDeclaration,
1563 ));
1564 }
1565 Importance::Important
1566 },
1567 Err(_) => Importance::Normal,
1568 };
1569 input.expect_exhausted()?;
1571 let has_parsed_declarations = self.has_parsed_declarations();
1572 self.output_block
1573 .extend(self.declarations.drain(), self.importance);
1574 self.last_parsed_property_id = None;
1578
1579 if !has_parsed_declarations {
1580 self.first_declaration_start = declaration_start.source_location();
1581 }
1582
1583 Ok(())
1584 }
1585
1586 #[inline]
1588 pub fn report_errors_if_needed(
1589 &mut self,
1590 context: &ParserContext,
1591 selectors: &[SelectorList<SelectorImpl>],
1592 ) {
1593 if self.errors.is_empty() {
1594 return;
1595 }
1596 self.do_report_css_errors(context, selectors);
1597 }
1598
1599 #[cold]
1600 fn do_report_css_errors(
1601 &mut self,
1602 context: &ParserContext,
1603 selectors: &[SelectorList<SelectorImpl>],
1604 ) {
1605 for (error, slice, location, property) in self.errors.drain(..) {
1606 report_one_css_error(
1607 context,
1608 Some(&self.output_block),
1609 selectors,
1610 error,
1611 slice,
1612 location,
1613 property,
1614 )
1615 }
1616 }
1617
1618 #[inline]
1620 pub fn did_error(
1621 &mut self,
1622 context: &ParserContext,
1623 error: ParseError,
1624 slice: &'i str,
1625 location: SourceLocation,
1626 ) {
1627 self.declarations.clear();
1628 if !context.error_reporting_enabled() {
1629 return;
1630 }
1631 let property = self.last_parsed_property_id.take();
1632 self.errors.push((error, slice, location, property));
1633 }
1634}
1635
1636impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1638 type Prelude = ();
1639 type AtRule = ();
1640 type Error = StyleParseErrorKind;
1641}
1642
1643impl<'a, 'b, 'i> QualifiedRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1645 type Prelude = ();
1646 type QualifiedRule = ();
1647 type Error = StyleParseErrorKind;
1648}
1649
1650fn is_non_mozilla_vendor_identifier(name: &str) -> bool {
1652 (name.starts_with("-") && !name.starts_with("-moz-")) || name.starts_with("_")
1653}
1654
1655impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1656 type Declaration = ();
1657 type Error = StyleParseErrorKind;
1658
1659 fn parse_value(
1660 &mut self,
1661 name: CowRcStr<'i>,
1662 input: &mut Parser<'i>,
1663 declaration_start: &ParserState,
1664 ) -> Result<(), ParseError> {
1665 self.state
1666 .parse_value(self.context, name, input, declaration_start)
1667 }
1668}
1669
1670impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind>
1671 for PropertyDeclarationParser<'a, 'b, 'i>
1672{
1673 fn parse_declarations(&self) -> bool {
1674 true
1675 }
1676 fn parse_qualified(&self) -> bool {
1678 false
1679 }
1680}
1681
1682type SmallParseErrorVec<'i> =
1683 SmallVec<[(ParseError, &'i str, SourceLocation, Option<PropertyId>); 2]>;
1684
1685fn alias_of_known_property(name: &str) -> Option<PropertyId> {
1686 let mut prefixed = String::with_capacity(name.len() + 5);
1687 prefixed.push_str("-moz-");
1688 prefixed.push_str(name);
1689 PropertyId::parse_enabled_for_all_content(&prefixed).ok()
1690}
1691
1692#[cold]
1693fn report_one_css_error(
1694 context: &ParserContext,
1695 block: Option<&PropertyDeclarationBlock>,
1696 selectors: &[SelectorList<SelectorImpl>],
1697 mut error: ParseError,
1698 slice: &str,
1699 location: SourceLocation,
1700 property: Option<PropertyId>,
1701) {
1702 debug_assert!(context.error_reporting_enabled());
1703
1704 fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool {
1705 match property.as_shorthand() {
1706 Ok(id) => id
1707 .longhands()
1708 .all(|longhand| block.contains(PropertyDeclarationId::Longhand(longhand))),
1709 Err(longhand_or_custom) => block.contains(longhand_or_custom),
1710 }
1711 }
1712
1713 let mut error_string = Cow::Borrowed(slice);
1714 if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty) = error.kind {
1715 let name = slice.split(':').next().unwrap_or("").trim();
1718 if is_non_mozilla_vendor_identifier(name) {
1719 return;
1722 }
1723 if let Some(alias) = alias_of_known_property(name) {
1724 if let Some(block) = block {
1728 if all_properties_in_block(block, &alias) {
1729 return;
1730 }
1731 }
1732 }
1733 if !name.is_empty() {
1734 error_string = Cow::Borrowed(name);
1736 }
1737 }
1738
1739 if let Some(ref property) = property {
1740 if let Some(block) = block {
1741 if all_properties_in_block(block, property) {
1742 return;
1743 }
1744 }
1745 if !matches!(
1749 error.kind,
1750 ParseErrorKind::Custom(StyleParseErrorKind::UnexpectedImportantDeclaration)
1751 ) {
1752 error = ParseError::custom(StyleParseErrorKind::OtherInvalidValue);
1753 }
1754 if !slice.contains(':') {
1755 error_string = Cow::Owned(format!("{}: {slice}", property.to_css_string()));
1757 }
1758 }
1759
1760 let error =
1761 ContextualParseError::UnsupportedPropertyDeclaration(&error_string, error, selectors);
1762 context.log_css_error(location, error);
1763}
1764
1765pub fn parse_property_declaration_list(
1768 context: &ParserContext,
1769 input: &mut Parser,
1770 selectors: &[SelectorList<SelectorImpl>],
1771) -> PropertyDeclarationBlock {
1772 let mut state = DeclarationParserState::default();
1773 let mut parser = PropertyDeclarationParser {
1774 context,
1775 state: &mut state,
1776 };
1777 let mut iter = RuleBodyParser::new(input, &mut parser);
1778 while let Some(declaration) = iter.next() {
1779 match declaration {
1780 Ok(()) => {},
1781 Err((error, slice, location)) => {
1782 iter.parser.state.did_error(context, error, slice, location)
1783 },
1784 }
1785 }
1786 parser.state.report_errors_if_needed(context, selectors);
1787 state.output_block
1788}