1#![deny(missing_docs)]
8
9use super::{
10 AllShorthand, ComputedValues, LogicalGroupSet, LonghandIdSet, LonghandIdSetIterator,
11 NonCustomPropertyId, NonCustomPropertyIdSet, PropertyDeclaration, PropertyDeclarationId,
12 PropertyId, ShorthandId, SourcePropertyDeclaration, SourcePropertyDeclarationDrain,
13 SubpropertiesVec, property_counts,
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 StyleBuilder,
24 animated_properties::{AnimationValue, AnimationValueMap},
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 AtRuleParser, CowRcStr, DeclarationParser, Delimiter, ParseErrorKind, Parser, ParserState,
38 QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, parse_important,
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, Default)]
99pub enum Importance {
100 #[default]
102 Normal,
103
104 Important,
106}
107
108impl Importance {
109 pub fn important(self) -> bool {
111 match self {
112 Self::Normal => false,
113 Self::Important => true,
114 }
115 }
116}
117
118#[derive(Clone, Debug, ToShmem, Default, MallocSizeOf)]
120pub struct PropertyDeclarationIdSet {
121 longhands: LonghandIdSet,
122 custom: PrecomputedHashSet<custom_properties::Name>,
123}
124
125impl PropertyDeclarationIdSet {
126 pub fn insert(&mut self, id: PropertyDeclarationId) -> bool {
128 match id {
129 PropertyDeclarationId::Longhand(id) => {
130 if self.longhands.contains(id) {
131 return false;
132 }
133 self.longhands.insert(id);
134 true
135 },
136 PropertyDeclarationId::Custom(name) => self.custom.insert((*name).clone()),
137 }
138 }
139
140 pub fn contains(&self, id: PropertyDeclarationId) -> bool {
142 match id {
143 PropertyDeclarationId::Longhand(id) => self.longhands.contains(id),
144 PropertyDeclarationId::Custom(name) => self.custom.contains(name),
145 }
146 }
147
148 pub fn remove(&mut self, id: PropertyDeclarationId) {
150 match id {
151 PropertyDeclarationId::Longhand(id) => self.longhands.remove(id),
152 PropertyDeclarationId::Custom(name) => {
153 self.custom.remove(name);
154 },
155 }
156 }
157
158 pub fn clear(&mut self) {
160 self.longhands.clear();
161 self.custom.clear();
162 }
163
164 #[inline]
166 pub fn is_empty(&self) -> bool {
167 self.longhands.is_empty() && self.custom.is_empty()
168 }
169 #[inline]
171 pub fn contains_any_reset(&self) -> bool {
172 self.longhands.contains_any_reset()
173 }
174
175 #[inline]
177 pub fn contains_all_longhands(&self, longhands: &LonghandIdSet) -> bool {
178 self.longhands.contains_all(longhands)
179 }
180
181 #[inline]
183 pub fn contains_all(&self, properties: &PropertyDeclarationIdSet) -> bool {
184 if !self.longhands.contains_all(&properties.longhands) {
185 return false;
186 }
187 if properties.custom.len() > self.custom.len() {
188 return false;
189 }
190 properties
191 .custom
192 .iter()
193 .all(|item| self.custom.contains(item))
194 }
195
196 pub fn iter(&self) -> PropertyDeclarationIdSetIterator<'_> {
198 PropertyDeclarationIdSetIterator {
199 longhands: self.longhands.iter(),
200 custom: self.custom.iter(),
201 }
202 }
203}
204
205pub struct PropertyDeclarationIdSetIterator<'a> {
207 longhands: LonghandIdSetIterator<'a>,
208 custom: hashbrown::hash_set::Iter<'a, custom_properties::Name>,
209}
210
211impl<'a> Iterator for PropertyDeclarationIdSetIterator<'a> {
212 type Item = PropertyDeclarationId<'a>;
213
214 fn next(&mut self) -> Option<Self::Item> {
215 match self.longhands.next() {
219 Some(id) => Some(PropertyDeclarationId::Longhand(id)),
220 None => self.custom.next().map(PropertyDeclarationId::Custom),
221 }
222 }
223}
224
225#[derive(Default, MallocSizeOf)]
227pub struct PropertyDeclarationBlock {
228 declarations: ThinVec<PropertyDeclaration>,
232
233 declarations_importance: SmallBitVec,
235
236 property_ids: PropertyDeclarationIdSet,
238
239 pub immutable: AtomicBool,
243}
244
245impl to_shmem::ToShmem for PropertyDeclarationBlock {
246 fn to_shmem(&self, builder: &mut to_shmem::SharedMemoryBuilder) -> to_shmem::Result<Self> {
247 use std::mem::ManuallyDrop;
248 let declarations = self.declarations.to_shmem(builder)?;
249 let declarations_importance = self.declarations_importance.to_shmem(builder)?;
250 let property_ids = self.property_ids.to_shmem(builder)?;
251 let immutable = AtomicBool::new(true);
252
253 Ok(ManuallyDrop::new(Self {
254 declarations: ManuallyDrop::into_inner(declarations),
255 declarations_importance: ManuallyDrop::into_inner(declarations_importance),
256 property_ids: ManuallyDrop::into_inner(property_ids),
257 immutable,
258 }))
259 }
260}
261
262impl Clone for PropertyDeclarationBlock {
263 fn clone(&self) -> Self {
264 Self {
265 declarations: self.declarations.clone(),
266 declarations_importance: self.declarations_importance.clone(),
267 property_ids: self.property_ids.clone(),
268 immutable: AtomicBool::new(false),
269 }
270 }
271}
272
273impl PartialEq for PropertyDeclarationBlock {
274 fn eq(&self, other: &Self) -> bool {
275 self.declarations == other.declarations
279 && self.declarations_importance == other.declarations_importance
280 }
281}
282
283pub struct DeclarationImportanceIterator<'a> {
285 iter: Zip<Iter<'a, PropertyDeclaration>, smallbitvec::Iter<'a>>,
286}
287
288impl<'a> Default for DeclarationImportanceIterator<'a> {
289 fn default() -> Self {
290 Self {
291 iter: [].iter().zip(smallbitvec::Iter::default()),
292 }
293 }
294}
295
296impl<'a> DeclarationImportanceIterator<'a> {
297 fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
299 DeclarationImportanceIterator {
300 iter: declarations.iter().zip(important.iter()),
301 }
302 }
303}
304
305impl<'a> Iterator for DeclarationImportanceIterator<'a> {
306 type Item = (&'a PropertyDeclaration, Importance);
307
308 #[inline]
309 fn next(&mut self) -> Option<Self::Item> {
310 self.iter.next().map(|(decl, important)| {
311 (
312 decl,
313 if important {
314 Importance::Important
315 } else {
316 Importance::Normal
317 },
318 )
319 })
320 }
321
322 #[inline]
323 fn size_hint(&self) -> (usize, Option<usize>) {
324 self.iter.size_hint()
325 }
326}
327
328impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
329 #[inline(always)]
330 fn next_back(&mut self) -> Option<Self::Item> {
331 self.iter.next_back().map(|(decl, important)| {
332 (
333 decl,
334 if important {
335 Importance::Important
336 } else {
337 Importance::Normal
338 },
339 )
340 })
341 }
342}
343
344pub struct AnimationValueIterator<'a, 'cx, 'cx_a: 'cx> {
346 iter: DeclarationImportanceIterator<'a>,
347 context: &'cx mut Context<'cx_a>,
348 style: &'a ComputedValues,
349 default_values: &'a ComputedValues,
350}
351
352impl<'a, 'cx, 'cx_a: 'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
353 fn new(
354 declarations: &'a PropertyDeclarationBlock,
355 context: &'cx mut Context<'cx_a>,
356 style: &'a ComputedValues,
357 default_values: &'a ComputedValues,
358 ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
359 AnimationValueIterator {
360 iter: declarations.declaration_importance_iter(),
361 context,
362 style,
363 default_values,
364 }
365 }
366}
367
368impl<'a, 'cx, 'cx_a: 'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
369 type Item = AnimationValue;
370 #[inline]
371 fn next(&mut self) -> Option<Self::Item> {
372 loop {
373 let (decl, importance) = self.iter.next()?;
374
375 if importance.important() {
376 continue;
377 }
378
379 let animation = AnimationValue::from_declaration(
380 decl,
381 self.context,
382 self.style,
383 self.default_values,
384 &mut AttributeTracker::new_dummy(),
386 );
387
388 if let Some(anim) = animation {
389 return Some(anim);
390 }
391 }
392 }
393}
394
395impl fmt::Debug for PropertyDeclarationBlock {
396 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397 self.declarations.fmt(f)
398 }
399}
400
401impl PropertyDeclarationBlock {
402 #[inline]
404 pub fn len(&self) -> usize {
405 self.declarations.len()
406 }
407
408 #[inline]
410 pub fn is_empty(&self) -> bool {
411 self.declarations.is_empty()
412 }
413
414 #[inline]
416 pub fn new() -> Self {
417 PropertyDeclarationBlock {
418 declarations: ThinVec::new(),
419 declarations_importance: SmallBitVec::new(),
420 property_ids: PropertyDeclarationIdSet::default(),
421 immutable: AtomicBool::new(false),
422 }
423 }
424
425 pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
427 let mut property_ids = PropertyDeclarationIdSet::default();
428 property_ids.insert(declaration.id());
429 let mut declarations = ThinVec::with_capacity(1);
430 declarations.push(declaration);
431 PropertyDeclarationBlock {
432 declarations,
433 declarations_importance: SmallBitVec::from_elem(1, importance.important()),
434 property_ids,
435 immutable: AtomicBool::new(false),
436 }
437 }
438
439 #[inline]
441 pub fn declarations(&self) -> &[PropertyDeclaration] {
442 &self.declarations
443 }
444
445 #[inline]
447 pub fn declarations_importance(&self) -> &SmallBitVec {
448 &self.declarations_importance
449 }
450
451 #[inline]
453 pub fn declaration_importance_iter(&self) -> DeclarationImportanceIterator<'_> {
454 DeclarationImportanceIterator::new(&self.declarations, &self.declarations_importance)
455 }
456
457 #[inline]
459 pub fn normal_declaration_iter(&self) -> impl DoubleEndedIterator<Item = &PropertyDeclaration> {
460 self.declaration_importance_iter()
461 .filter(|(_, importance)| !importance.important())
462 .map(|(declaration, _)| declaration)
463 }
464
465 #[inline]
467 pub fn to_animation_value_iter<'a, 'cx, 'cx_a: 'cx>(
468 &'a self,
469 context: &'cx mut Context<'cx_a>,
470 style: &'a ComputedValues,
471 default_values: &'a ComputedValues,
472 ) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
473 AnimationValueIterator::new(self, context, style, default_values)
474 }
475
476 #[inline]
481 pub fn any_important(&self) -> bool {
482 !self.declarations_importance.all_false()
483 }
484
485 #[inline]
490 pub fn any_normal(&self) -> bool {
491 !self.declarations_importance.all_true()
492 }
493
494 #[inline]
497 pub fn property_ids(&self) -> &PropertyDeclarationIdSet {
498 &self.property_ids
499 }
500
501 #[inline]
503 pub fn contains(&self, id: PropertyDeclarationId) -> bool {
504 self.property_ids.contains(id)
505 }
506
507 #[inline]
509 pub fn contains_any_reset(&self) -> bool {
510 self.property_ids.contains_any_reset()
511 }
512
513 #[inline]
518 pub fn get(
519 &self,
520 property: PropertyDeclarationId,
521 ) -> Option<(&PropertyDeclaration, Importance)> {
522 if !self.contains(property) {
523 return None;
524 }
525 self.declaration_importance_iter()
526 .find(|(declaration, _)| declaration.id() == property)
527 }
528
529 pub fn shorthand_to_css(
532 &self,
533 shorthand: ShorthandId,
534 dest: &mut CssStringWriter,
535 ) -> fmt::Result {
536 let mut list = SmallVec::<[&_; 10]>::new();
539 let mut important_count = 0;
540
541 for longhand in shorthand.longhands() {
543 let declaration = self.get(PropertyDeclarationId::Longhand(longhand));
545
546 match declaration {
548 Some((declaration, importance)) => {
549 list.push(declaration);
550 if importance.important() {
551 important_count += 1;
552 }
553 },
554 None => return Ok(()),
555 }
556 }
557
558 if important_count > 0 && important_count != list.len() {
561 return Ok(());
562 }
563
564 match shorthand.get_shorthand_appendable_value(&list) {
568 Some(appendable_value) => append_declaration_value(dest, appendable_value),
569 None => Ok(()),
570 }
571 }
572
573 pub fn property_value_to_css(
577 &self,
578 property: &PropertyId,
579 dest: &mut CssStringWriter,
580 ) -> fmt::Result {
581 let longhand_or_custom = match property.as_shorthand() {
585 Ok(shorthand) => return self.shorthand_to_css(shorthand, dest),
586 Err(longhand_or_custom) => longhand_or_custom,
587 };
588
589 if let Some((value, _importance)) = self.get(longhand_or_custom) {
590 value.to_css(dest)
592 } else {
593 Ok(())
595 }
596 }
597
598 pub fn property_priority(&self, property: &PropertyId) -> Importance {
600 match property.as_shorthand() {
604 Ok(shorthand) => {
605 if shorthand.longhands().all(|l| {
607 self.get(PropertyDeclarationId::Longhand(l))
608 .is_some_and(|(_, importance)| importance.important())
609 }) {
610 Importance::Important
611 } else {
612 Importance::Normal
613 }
614 },
615 Err(longhand_or_custom) => {
616 self.get(longhand_or_custom)
618 .map_or(Importance::Normal, |(_, importance)| importance)
619 },
620 }
621 }
622
623 pub fn property_value_to_typed_value_list(
627 &self,
628 property: &PropertyId,
629 ) -> Result<Option<TypedValueList>, ()> {
630 match property.as_shorthand() {
631 Ok(shorthand) => {
632 if shorthand
633 .longhands()
634 .all(|longhand| self.contains(PropertyDeclarationId::Longhand(longhand)))
635 {
636 Ok(None)
637 } else {
638 Err(())
639 }
640 },
641 Err(longhand_or_custom) => match self.get(longhand_or_custom) {
642 Some((value, _importance)) => Ok(value.to_typed_value_list()),
643 None => Err(()),
644 },
645 }
646 }
647
648 pub fn extend(
653 &mut self,
654 mut drain: SourcePropertyDeclarationDrain,
655 importance: Importance,
656 ) -> bool {
657 let all_shorthand_len = match drain.all_shorthand {
658 AllShorthand::NotSet => 0,
659 AllShorthand::CSSWideKeyword(_) | AllShorthand::WithVariables(_) => {
660 property_counts::ALL_SHORTHAND_EXPANDED
661 },
662 };
663 let push_calls_count = drain.declarations.len() + all_shorthand_len;
664
665 self.declarations.reserve(push_calls_count);
667
668 let mut changed = false;
669 for decl in &mut drain.declarations {
670 changed |= self.push(decl, importance);
671 }
672 drain
673 .all_shorthand
674 .declarations()
675 .fold(changed, |changed, decl| {
676 changed | self.push(decl, importance)
677 })
678 }
679
680 pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) -> bool {
686 let id = declaration.id();
687 if !self.property_ids.insert(id) {
688 let mut index_to_remove = None;
689 for (i, slot) in self.declarations.iter_mut().enumerate() {
690 if slot.id() != id {
691 continue;
692 }
693
694 let important = self.declarations_importance[i];
695
696 if important && !importance.important() {
699 return false;
700 }
701
702 index_to_remove = Some(i);
703 break;
704 }
705
706 if let Some(index) = index_to_remove {
707 self.declarations.remove(index);
708 self.declarations_importance.remove(index);
709 self.declarations.push(declaration);
710 self.declarations_importance.push(importance.important());
711 return true;
712 }
713 }
714
715 self.declarations.push(declaration);
716 self.declarations_importance.push(importance.important());
717 true
718 }
719
720 pub fn prepare_for_update(
724 &self,
725 source_declarations: &SourcePropertyDeclaration,
726 importance: Importance,
727 updates: &mut SourcePropertyDeclarationUpdate,
728 ) -> bool {
729 debug_assert!(updates.updates.is_empty());
730 if !matches!(source_declarations.all_shorthand, AllShorthand::NotSet) {
732 debug_assert!(source_declarations.declarations.is_empty());
733 return source_declarations
734 .all_shorthand
735 .declarations()
736 .any(|decl| {
737 !self.contains(decl.id())
738 || self
739 .declarations
740 .iter()
741 .enumerate()
742 .find(|&(_, d)| d.id() == decl.id())
743 .is_none_or(|(i, d)| {
744 let important = self.declarations_importance[i];
745 *d != decl || important != importance.important()
746 })
747 });
748 }
749 let mut any_update = false;
751 let new_count = &mut updates.new_count;
752 let any_removal = &mut updates.any_removal;
753 let updates = &mut updates.updates;
754 updates.extend(
755 source_declarations
756 .declarations
757 .iter()
758 .map(|declaration| {
759 if !self.contains(declaration.id()) {
760 return DeclarationUpdate::Append;
761 }
762 let longhand_id = declaration.id().as_longhand();
763 if let Some(longhand_id) = longhand_id
764 && let Some(logical_group) = longhand_id.logical_group()
765 {
766 let mut needs_append = false;
767 for (pos, decl) in self.declarations.iter().enumerate().rev() {
768 let id = match decl.id().as_longhand() {
769 Some(id) => id,
770 None => continue,
771 };
772 if id == longhand_id {
773 if needs_append {
774 return DeclarationUpdate::AppendAndRemove { pos };
775 }
776 let important = self.declarations_importance[pos];
777 if decl == declaration && important == importance.important() {
778 return DeclarationUpdate::None;
779 }
780 return DeclarationUpdate::UpdateInPlace { pos };
781 }
782 if !needs_append
783 && id.logical_group() == Some(logical_group)
784 && id.is_logical() != longhand_id.is_logical()
785 {
786 needs_append = true;
787 }
788 }
789 unreachable!("Longhand should be found in loop above");
790 }
791 self.declarations
792 .iter()
793 .enumerate()
794 .find(|&(_, decl)| decl.id() == declaration.id())
795 .map_or(DeclarationUpdate::Append, |(pos, decl)| {
796 let important = self.declarations_importance[pos];
797 if decl == declaration && important == importance.important() {
798 DeclarationUpdate::None
799 } else {
800 DeclarationUpdate::UpdateInPlace { pos }
801 }
802 })
803 })
804 .inspect(|update| {
805 if matches!(update, DeclarationUpdate::None) {
806 return;
807 }
808 any_update = true;
809 match update {
810 DeclarationUpdate::Append => {
811 *new_count += 1;
812 },
813 DeclarationUpdate::AppendAndRemove { .. } => {
814 *any_removal = true;
815 },
816 _ => {},
817 }
818 }),
819 );
820 any_update
821 }
822
823 pub fn update(
825 &mut self,
826 drain: SourcePropertyDeclarationDrain,
827 importance: Importance,
828 updates: &mut SourcePropertyDeclarationUpdate,
829 ) {
830 let important = importance.important();
831 if !matches!(drain.all_shorthand, AllShorthand::NotSet) {
832 debug_assert!(updates.updates.is_empty());
833 for decl in drain.all_shorthand.declarations() {
834 let id = decl.id();
835 if self.property_ids.insert(id) {
836 self.declarations.push(decl);
837 self.declarations_importance.push(important);
838 } else {
839 let (idx, slot) = self
840 .declarations
841 .iter_mut()
842 .enumerate()
843 .find(|(_, d)| d.id() == decl.id())
844 .unwrap();
845 *slot = decl;
846 self.declarations_importance.set(idx, important);
847 }
848 }
849 return;
850 }
851
852 self.declarations.reserve(updates.new_count);
853 if updates.any_removal {
854 struct UpdateOrRemoval<'a> {
856 item: &'a mut DeclarationUpdate,
857 pos: usize,
858 remove: bool,
859 }
860 let mut updates_and_removals: SubpropertiesVec<UpdateOrRemoval> = updates
861 .updates
862 .iter_mut()
863 .filter_map(|item| {
864 let (pos, remove) = match *item {
865 DeclarationUpdate::UpdateInPlace { pos } => (pos, false),
866 DeclarationUpdate::AppendAndRemove { pos } => (pos, true),
867 _ => return None,
868 };
869 Some(UpdateOrRemoval { item, pos, remove })
870 })
871 .collect();
872 updates_and_removals.sort_unstable_by_key(|update| update.pos);
875 updates_and_removals
876 .iter()
877 .rev()
878 .filter(|update| update.remove)
879 .for_each(|update| {
880 self.declarations.remove(update.pos);
881 self.declarations_importance.remove(update.pos);
882 });
883 let mut removed_count = 0;
885 for update in updates_and_removals.iter_mut() {
886 if update.remove {
887 removed_count += 1;
888 continue;
889 }
890 debug_assert_eq!(
891 *update.item,
892 DeclarationUpdate::UpdateInPlace { pos: update.pos }
893 );
894 *update.item = DeclarationUpdate::UpdateInPlace {
895 pos: update.pos - removed_count,
896 };
897 }
898 }
899 for (decl, update) in drain.declarations.zip_eq(updates.updates.iter()) {
901 match *update {
902 DeclarationUpdate::None => {},
903 DeclarationUpdate::Append | DeclarationUpdate::AppendAndRemove { .. } => {
904 self.property_ids.insert(decl.id());
905 self.declarations.push(decl);
906 self.declarations_importance.push(important);
907 },
908 DeclarationUpdate::UpdateInPlace { pos } => {
909 self.declarations[pos] = decl;
910 self.declarations_importance.set(pos, important);
911 },
912 }
913 }
914 updates.updates.clear();
915 }
916
917 #[inline]
920 pub fn first_declaration_to_remove(&self, property: &PropertyId) -> Option<usize> {
921 if let Err(longhand_or_custom) = property.as_shorthand()
922 && !self.contains(longhand_or_custom)
923 {
924 return None;
925 }
926
927 self.declarations
928 .iter()
929 .position(|declaration| declaration.id().is_or_is_longhand_of(property))
930 }
931
932 #[inline]
934 fn remove_declaration_at(&mut self, i: usize) {
935 self.property_ids.remove(self.declarations[i].id());
936 self.declarations_importance.remove(i);
937 self.declarations.remove(i);
938 }
939
940 #[inline]
942 pub fn clear(&mut self) {
943 self.declarations_importance.clear();
944 self.declarations.clear();
945 self.property_ids.clear();
946 }
947
948 #[inline]
953 pub fn remove_property(&mut self, property: &PropertyId, first_declaration: usize) {
954 debug_assert_eq!(
955 Some(first_declaration),
956 self.first_declaration_to_remove(property)
957 );
958 debug_assert!(
959 self.declarations[first_declaration]
960 .id()
961 .is_or_is_longhand_of(property)
962 );
963
964 self.remove_declaration_at(first_declaration);
965
966 let shorthand = match property.as_shorthand() {
967 Ok(s) => s,
968 Err(_longhand_or_custom) => return,
969 };
970
971 let mut i = first_declaration;
972 let mut len = self.len();
973 while i < len {
974 if !self.declarations[i].id().is_longhand_of(shorthand) {
975 i += 1;
976 continue;
977 }
978
979 self.remove_declaration_at(i);
980 len -= 1;
981 }
982 }
983
984 pub fn single_value_to_css(
986 &self,
987 property: &PropertyId,
988 dest: &mut CssStringWriter,
989 computed_values: Option<&ComputedValues>,
990 stylist: &Stylist,
991 ) -> fmt::Result {
992 if let Ok(shorthand) = property.as_shorthand() {
993 return self.shorthand_to_css(shorthand, dest);
994 }
995
996 let declaration = match self.declarations.first() {
999 Some(d) => d,
1000 None => return Err(fmt::Error),
1001 };
1002
1003 let mut rule_cache_conditions = RuleCacheConditions::default();
1004 let mut tree_counting_caches = TreeCountingCaches::default();
1005 let mut context = Context::new(
1006 StyleBuilder::new(
1007 stylist.device(),
1008 Some(stylist),
1009 computed_values,
1010 None,
1011 None,
1012 false,
1013 ),
1014 stylist.quirks_mode(),
1015 &mut rule_cache_conditions,
1016 ContainerSizeQuery::none(),
1017 RuleCascadeFlags::empty(),
1018 &DummyElementContext {},
1019 &mut tree_counting_caches,
1020 );
1021
1022 if let Some(cv) = computed_values {
1023 context.builder.substitution_functions.custom_properties =
1024 cv.custom_properties().clone();
1025 };
1026
1027 match (declaration, computed_values) {
1028 (PropertyDeclaration::WithVariables(declaration), Some(_)) => declaration
1036 .value
1037 .substitute_variables(
1038 declaration.id,
1039 &context.builder.substitution_functions,
1040 stylist,
1041 &context,
1042 &mut Default::default(),
1043 &mut AttributeTracker::new_dummy(),
1044 )
1045 .to_css(dest),
1046 (d, _) => d.to_css(dest),
1047 }
1048 }
1049
1050 pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self {
1052 let len = animation_value_map.len();
1053 let mut declarations = ThinVec::with_capacity(len);
1054 let mut property_ids = PropertyDeclarationIdSet::default();
1055
1056 for (property, animation_value) in animation_value_map.iter() {
1057 property_ids.insert(property.as_borrowed());
1058 declarations.push(animation_value.uncompute());
1059 }
1060
1061 PropertyDeclarationBlock {
1062 declarations,
1063 property_ids,
1064 declarations_importance: SmallBitVec::from_elem(len, false),
1065 immutable: AtomicBool::new(false),
1066 }
1067 }
1068
1069 pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
1072 if let Err(longhand_or_custom) = property.as_shorthand()
1073 && !self.property_ids.contains(longhand_or_custom)
1074 {
1075 return false;
1076 }
1077 self.declarations.iter().any(|decl| {
1078 decl.id().is_or_is_longhand_of(property) && decl.get_css_wide_keyword().is_some()
1079 })
1080 }
1081
1082 pub fn to_css(&self, dest: &mut CssStringWriter) -> fmt::Result {
1088 let mut is_first_serialization = true; let mut already_serialized = NonCustomPropertyIdSet::new();
1100
1101 'declaration_loop: for (declaration, importance) in self.declaration_importance_iter() {
1103 let property = declaration.id();
1105 let longhand_id = match property {
1106 PropertyDeclarationId::Longhand(id) => id,
1107 PropertyDeclarationId::Custom(..) => {
1108 append_serialization(
1113 dest,
1114 &property,
1115 AppendableValue::Declaration(declaration),
1116 importance,
1117 &mut is_first_serialization,
1118 )?;
1119 continue;
1120 },
1121 };
1122
1123 if already_serialized.contains(longhand_id.into()) {
1125 continue;
1126 }
1127
1128 for shorthand in longhand_id.shorthands() {
1130 if already_serialized.contains(shorthand.into()) {
1132 continue;
1133 }
1134 already_serialized.insert(shorthand.into());
1135
1136 if shorthand.is_legacy_shorthand()
1137 && !(shorthand.allows_disabled_subproperties()
1138 && !NonCustomPropertyId::from(longhand_id).enabled_for_all_content())
1139 {
1140 continue;
1142 }
1143
1144 let longhands = {
1151 let mut ids = LonghandIdSet::new();
1154 for longhand in shorthand.longhands() {
1155 ids.insert(longhand);
1156 }
1157 ids
1158 };
1159
1160 if !self.property_ids.contains_all_longhands(&longhands) {
1165 continue;
1166 }
1167
1168 let mut current_longhands = SmallVec::<[&_; 10]>::new();
1171 let mut logical_groups = LogicalGroupSet::new();
1172 let mut saw_one = false;
1173 let mut logical_mismatch = false;
1174 let mut seen = LonghandIdSet::new();
1175 let mut important_count = 0;
1176
1177 for (declaration, importance) in self.declaration_importance_iter() {
1181 let longhand = match declaration.id() {
1182 PropertyDeclarationId::Longhand(id) => id,
1183 PropertyDeclarationId::Custom(..) => continue,
1184 };
1185
1186 if longhands.contains(longhand) {
1187 saw_one = true;
1188 if importance.important() {
1189 important_count += 1;
1190 }
1191 current_longhands.push(declaration);
1192 if shorthand != ShorthandId::All {
1193 if let Some(g) = longhand.logical_group() {
1196 logical_groups.insert(g);
1197 }
1198 seen.insert(longhand);
1199 if seen == longhands {
1200 break;
1201 }
1202 }
1203 } else if saw_one
1204 && let Some(g) = longhand.logical_group()
1205 && logical_groups.contains(g)
1206 {
1207 logical_mismatch = true;
1208 break;
1209 }
1210 }
1211
1212 let is_important = important_count > 0;
1218 if is_important && important_count != current_longhands.len() {
1219 continue;
1220 }
1221
1222 if logical_mismatch {
1230 continue;
1231 }
1232
1233 let importance = if is_important {
1234 Importance::Important
1235 } else {
1236 Importance::Normal
1237 };
1238
1239 let appendable_value =
1243 match shorthand.get_shorthand_appendable_value(¤t_longhands) {
1244 None => continue,
1245 Some(appendable_value) => appendable_value,
1246 };
1247
1248 let mut v = CssString::new();
1251 let value = match appendable_value {
1252 AppendableValue::Css(css) => {
1253 debug_assert!(!css.is_empty());
1254 appendable_value
1255 },
1256 other => {
1257 append_declaration_value(&mut v, other)?;
1258
1259 if v.is_empty() {
1263 continue;
1264 }
1265
1266 AppendableValue::Css({
1267 #[cfg(feature = "gecko")]
1269 unsafe {
1270 v.as_str_unchecked()
1271 }
1272 #[cfg(feature = "servo")]
1273 &v
1274 })
1275 },
1276 };
1277
1278 append_serialization(
1288 dest,
1289 &shorthand,
1290 value,
1291 importance,
1292 &mut is_first_serialization,
1293 )?;
1294
1295 for current_longhand in ¤t_longhands {
1299 let longhand_id = match current_longhand.id() {
1300 PropertyDeclarationId::Longhand(id) => id,
1301 PropertyDeclarationId::Custom(..) => unreachable!(),
1302 };
1303
1304 already_serialized.insert(longhand_id.into());
1306 }
1307
1308 continue 'declaration_loop;
1311 }
1312
1313 append_serialization(
1324 dest,
1325 &property,
1326 AppendableValue::Declaration(declaration),
1327 importance,
1328 &mut is_first_serialization,
1329 )?;
1330
1331 already_serialized.insert(longhand_id.into());
1334 }
1335
1336 Ok(())
1338 }
1339}
1340
1341pub enum AppendableValue<'a, 'b: 'a> {
1344 Declaration(&'a PropertyDeclaration),
1346 DeclarationsForShorthand(ShorthandId, &'a [&'b PropertyDeclaration]),
1351 Css(&'a str),
1354}
1355
1356fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result
1358where
1359 W: Write,
1360{
1361 if !*is_first_serialization {
1362 dest.write_char(' ')
1363 } else {
1364 *is_first_serialization = false;
1365 Ok(())
1366 }
1367}
1368
1369pub fn append_declaration_value<'a, 'b: 'a>(
1371 dest: &mut CssStringWriter,
1372 appendable_value: AppendableValue<'a, 'b>,
1373) -> fmt::Result {
1374 match appendable_value {
1375 AppendableValue::Css(css) => dest.write_str(css),
1376 AppendableValue::Declaration(decl) => decl.to_css(dest),
1377 AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
1378 shorthand.longhands_to_css(decls, dest)
1379 },
1380 }
1381}
1382
1383pub fn append_serialization<'a, 'b: 'a, N>(
1385 dest: &mut CssStringWriter,
1386 property_name: &N,
1387 appendable_value: AppendableValue<'a, 'b>,
1388 importance: Importance,
1389 is_first_serialization: &mut bool,
1390) -> fmt::Result
1391where
1392 N: ToCss,
1393{
1394 handle_first_serialization(dest, is_first_serialization)?;
1395
1396 property_name.to_css(&mut CssWriter::new(dest))?;
1397 dest.write_str(": ")?;
1398
1399 append_declaration_value(dest, appendable_value)?;
1400
1401 if importance.important() {
1402 dest.write_str(" !important")?;
1403 }
1404
1405 dest.write_char(';')
1406}
1407
1408#[inline]
1413pub fn parse_style_attribute(
1414 input: &str,
1415 url_data: &UrlExtraData,
1416 error_reporter: Option<&dyn ParseErrorReporter>,
1417 quirks_mode: QuirksMode,
1418 rule_type: CssRuleType,
1419) -> PropertyDeclarationBlock {
1420 let mut context = ParserContext::new(
1421 Origin::Author,
1422 url_data,
1423 Some(rule_type),
1424 ParsingMode::DEFAULT,
1425 quirks_mode,
1426 Default::default(),
1427 error_reporter,
1428 None,
1429 Default::default(),
1430 );
1431
1432 parse_property_declaration_list(&mut context, &mut Parser::new(input), &[])
1433}
1434
1435#[inline]
1440pub fn parse_one_declaration_into(
1441 declarations: &mut SourcePropertyDeclaration,
1442 id: PropertyId,
1443 input: &str,
1444 origin: Origin,
1445 url_data: &UrlExtraData,
1446 error_reporter: Option<&dyn ParseErrorReporter>,
1447 parsing_mode: ParsingMode,
1448 quirks_mode: QuirksMode,
1449 rule_type: CssRuleType,
1450) -> Result<(), ()> {
1451 let mut context = ParserContext::new(
1452 origin,
1453 url_data,
1454 Some(rule_type),
1455 parsing_mode,
1456 quirks_mode,
1457 Default::default(),
1458 error_reporter,
1459 None,
1460 Default::default(),
1461 );
1462
1463 let property_id_for_error_reporting = if context.error_reporting_enabled() {
1464 Some(id.clone())
1465 } else {
1466 None
1467 };
1468
1469 let mut parser = Parser::new(input);
1470 let start_position = parser.position();
1471 let start_location = parser.current_source_location();
1472 parser
1473 .parse_entirely(|parser| {
1474 PropertyDeclaration::parse_into(declarations, id, &mut context, parser)
1475 })
1476 .map_err(|err| {
1477 if context.error_reporting_enabled() {
1478 report_one_css_error(
1479 &context,
1480 None,
1481 &[],
1482 err,
1483 parser.slice_from(start_position),
1484 start_location,
1485 property_id_for_error_reporting,
1486 )
1487 }
1488 })
1489}
1490
1491struct PropertyDeclarationParser<'a, 'b: 'a, 'i> {
1493 context: &'a mut ParserContext<'b>,
1494 state: &'a mut DeclarationParserState<'i>,
1495}
1496
1497#[derive(Default)]
1501pub struct DeclarationParserState<'i> {
1502 output_block: PropertyDeclarationBlock,
1504 declarations: SourcePropertyDeclaration,
1507 importance: Importance,
1509 errors: SmallParseErrorVec<'i>,
1511 first_declaration_start: SourceLocation,
1513 last_parsed_property_id: Option<PropertyId>,
1515}
1516
1517impl<'i> DeclarationParserState<'i> {
1518 pub fn first_declaration_start(&self) -> SourceLocation {
1520 self.first_declaration_start
1521 }
1522
1523 pub fn has_parsed_declarations(&self) -> bool {
1525 !self.output_block.is_empty()
1526 }
1527
1528 pub fn take_declarations(&mut self) -> PropertyDeclarationBlock {
1530 std::mem::take(&mut self.output_block)
1531 }
1532
1533 pub fn parse_value(
1535 &mut self,
1536 context: &mut ParserContext,
1537 name: CowRcStr<'i>,
1538 input: &mut Parser<'i>,
1539 declaration_start: &ParserState,
1540 ) -> Result<(), ParseError> {
1541 let id = match PropertyId::parse(&name, context) {
1542 Ok(id) => id,
1543 Err(..) => {
1544 return Err(ParseError::custom(StyleParseErrorKind::UnknownProperty));
1545 },
1546 };
1547 if context.error_reporting_enabled() {
1548 self.last_parsed_property_id = Some(id.clone());
1549 }
1550 input.parse_until_before(Delimiter::Bang, |input| {
1551 PropertyDeclaration::parse_into(&mut self.declarations, id, context, input)
1552 })?;
1553 self.importance = match input.try_parse(parse_important) {
1554 Ok(()) => {
1555 if !context.allows_important_declarations() {
1556 return Err(ParseError::custom(
1557 StyleParseErrorKind::UnexpectedImportantDeclaration,
1558 ));
1559 }
1560 Importance::Important
1561 },
1562 Err(_) => Importance::Normal,
1563 };
1564 input.expect_exhausted()?;
1566 let has_parsed_declarations = self.has_parsed_declarations();
1567 self.output_block
1568 .extend(self.declarations.drain(), self.importance);
1569 self.last_parsed_property_id = None;
1573
1574 if !has_parsed_declarations {
1575 self.first_declaration_start = declaration_start.source_location();
1576 }
1577
1578 Ok(())
1579 }
1580
1581 #[inline]
1583 pub fn report_errors_if_needed(
1584 &mut self,
1585 context: &ParserContext,
1586 selectors: &[SelectorList<SelectorImpl>],
1587 ) {
1588 if self.errors.is_empty() {
1589 return;
1590 }
1591 self.do_report_css_errors(context, selectors);
1592 }
1593
1594 #[cold]
1595 fn do_report_css_errors(
1596 &mut self,
1597 context: &ParserContext,
1598 selectors: &[SelectorList<SelectorImpl>],
1599 ) {
1600 for (error, slice, location, property) in self.errors.drain(..) {
1601 report_one_css_error(
1602 context,
1603 Some(&self.output_block),
1604 selectors,
1605 error,
1606 slice,
1607 location,
1608 property,
1609 )
1610 }
1611 }
1612
1613 #[inline]
1615 pub fn did_error(
1616 &mut self,
1617 context: &ParserContext,
1618 error: ParseError,
1619 slice: &'i str,
1620 location: SourceLocation,
1621 ) {
1622 self.declarations.clear();
1623 if !context.error_reporting_enabled() {
1624 return;
1625 }
1626 let property = self.last_parsed_property_id.take();
1627 self.errors.push((error, slice, location, property));
1628 }
1629}
1630
1631impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1633 type Prelude = ();
1634 type AtRule = ();
1635 type Error = StyleParseErrorKind;
1636}
1637
1638impl<'a, 'b, 'i> QualifiedRuleParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1640 type Prelude = ();
1641 type QualifiedRule = ();
1642 type Error = StyleParseErrorKind;
1643}
1644
1645fn is_non_mozilla_vendor_identifier(name: &str) -> bool {
1647 (name.starts_with("-") && !name.starts_with("-moz-")) || name.starts_with("_")
1648}
1649
1650impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b, 'i> {
1651 type Declaration = ();
1652 type Error = StyleParseErrorKind;
1653
1654 fn parse_value(
1655 &mut self,
1656 name: CowRcStr<'i>,
1657 input: &mut Parser<'i>,
1658 declaration_start: &ParserState,
1659 ) -> Result<(), ParseError> {
1660 self.state
1661 .parse_value(self.context, name, input, declaration_start)
1662 }
1663}
1664
1665impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind>
1666 for PropertyDeclarationParser<'a, 'b, 'i>
1667{
1668 fn parse_declarations(&self) -> bool {
1669 true
1670 }
1671 fn parse_qualified(&self) -> bool {
1673 false
1674 }
1675}
1676
1677type SmallParseErrorVec<'i> =
1678 SmallVec<[(ParseError, &'i str, SourceLocation, Option<PropertyId>); 2]>;
1679
1680fn alias_of_known_property(name: &str) -> Option<PropertyId> {
1681 let mut prefixed = String::with_capacity(name.len() + 5);
1682 prefixed.push_str("-moz-");
1683 prefixed.push_str(name);
1684 PropertyId::parse_enabled_for_all_content(&prefixed).ok()
1685}
1686
1687#[cold]
1688fn report_one_css_error(
1689 context: &ParserContext,
1690 block: Option<&PropertyDeclarationBlock>,
1691 selectors: &[SelectorList<SelectorImpl>],
1692 mut error: ParseError,
1693 slice: &str,
1694 location: SourceLocation,
1695 property: Option<PropertyId>,
1696) {
1697 debug_assert!(context.error_reporting_enabled());
1698
1699 fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool {
1700 match property.as_shorthand() {
1701 Ok(id) => id
1702 .longhands()
1703 .all(|longhand| block.contains(PropertyDeclarationId::Longhand(longhand))),
1704 Err(longhand_or_custom) => block.contains(longhand_or_custom),
1705 }
1706 }
1707
1708 let mut error_string = Cow::Borrowed(slice);
1709 if let ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty) = error.kind {
1710 let name = slice.split(':').next().unwrap_or("").trim();
1713 if is_non_mozilla_vendor_identifier(name) {
1714 return;
1717 }
1718 if let Some(alias) = alias_of_known_property(name) {
1719 if let Some(block) = block
1723 && all_properties_in_block(block, &alias)
1724 {
1725 return;
1726 }
1727 }
1728 if !name.is_empty() {
1729 error_string = Cow::Borrowed(name);
1731 }
1732 }
1733
1734 if let Some(ref property) = property {
1735 if let Some(block) = block
1736 && all_properties_in_block(block, property)
1737 {
1738 return;
1739 }
1740 if !matches!(
1744 error.kind,
1745 ParseErrorKind::Custom(StyleParseErrorKind::UnexpectedImportantDeclaration)
1746 ) {
1747 error = ParseError::custom(StyleParseErrorKind::OtherInvalidValue);
1748 }
1749 if !slice.contains(':') {
1750 error_string = Cow::Owned(format!("{}: {slice}", property.to_css_string()));
1752 }
1753 }
1754
1755 let error =
1756 ContextualParseError::UnsupportedPropertyDeclaration(&error_string, error, selectors);
1757 context.log_css_error(location, error);
1758}
1759
1760pub fn parse_property_declaration_list(
1763 context: &mut ParserContext,
1764 input: &mut Parser,
1765 selectors: &[SelectorList<SelectorImpl>],
1766) -> PropertyDeclarationBlock {
1767 let mut state = DeclarationParserState::default();
1768 let mut parser = PropertyDeclarationParser {
1769 context,
1770 state: &mut state,
1771 };
1772 let mut iter = RuleBodyParser::new(input, &mut parser);
1773 while let Some(declaration) = iter.next() {
1774 match declaration {
1775 Ok(()) => {},
1776 Err((error, slice, location)) => {
1777 let parser = &mut *iter.parser;
1778 parser
1779 .state
1780 .did_error(parser.context, error, slice, location)
1781 },
1782 }
1783 }
1784 parser
1785 .state
1786 .report_errors_if_needed(parser.context, selectors);
1787 state.output_block
1788}