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