diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index d5cdb425022..d8ccf56b88b 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -9,11 +9,12 @@ use super::*; use crate::applicable_declarations::CascadePriority; use crate::context::QuirksMode; -use crate::custom_properties::CustomPropertiesBuilder; +use crate::custom_properties::{self, CustomPropertiesBuilder}; use crate::error_reporting::{ContextualParseError, ParseErrorReporter}; use crate::parser::ParserContext; use crate::properties::animated_properties::{AnimationValue, AnimationValueMap}; use crate::rule_tree::CascadeLevel; +use crate::selector_map::PrecomputedHashSet; use crate::selector_parser::SelectorImpl; use crate::shared_lock::Locked; use crate::str::{CssString, CssStringWriter}; @@ -29,6 +30,7 @@ use std::fmt::{self, Write}; use std::iter::{DoubleEndedIterator, Zip}; use std::slice::Iter; use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss}; +use thin_vec::ThinVec; /// A set of property declarations including animations and transitions. #[derive(Default)] @@ -92,6 +94,48 @@ impl Importance { } } +#[derive(Clone, ToShmem, Default, MallocSizeOf)] +struct PropertyDeclarationIdSet { + longhands: LonghandIdSet, + custom: PrecomputedHashSet, +} + +impl PropertyDeclarationIdSet { + fn insert(&mut self, id: PropertyDeclarationId) -> bool { + match id { + PropertyDeclarationId::Longhand(id) => { + if self.longhands.contains(id) { + return false; + } + self.longhands.insert(id); + return true; + }, + PropertyDeclarationId::Custom(name) => self.custom.insert(name.clone()), + } + } + + fn contains(&self, id: PropertyDeclarationId) -> bool { + match id { + PropertyDeclarationId::Longhand(id) => self.longhands.contains(id), + PropertyDeclarationId::Custom(name) => self.custom.contains(name), + } + } + + fn remove(&mut self, id: PropertyDeclarationId) { + match id { + PropertyDeclarationId::Longhand(id) => self.longhands.remove(id), + PropertyDeclarationId::Custom(name) => { + self.custom.remove(name); + }, + } + } + + fn clear(&mut self) { + self.longhands.clear(); + self.custom.clear(); + } +} + /// Overridden declarations are skipped. #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] #[derive(Clone, ToShmem)] @@ -99,12 +143,13 @@ pub struct PropertyDeclarationBlock { /// The group of declarations, along with their importance. /// /// Only deduplicated declarations appear here. - declarations: Vec, + declarations: ThinVec, /// The "important" flag for each declaration in `declarations`. declarations_importance: SmallBitVec, - longhands: LonghandIdSet, + /// The set of properties that are present in the block. + property_ids: PropertyDeclarationIdSet, } /// Iterator over `(PropertyDeclaration, Importance)` pairs. @@ -235,22 +280,22 @@ impl PropertyDeclarationBlock { #[inline] pub fn new() -> Self { PropertyDeclarationBlock { - declarations: Vec::new(), + declarations: ThinVec::new(), declarations_importance: SmallBitVec::new(), - longhands: LonghandIdSet::new(), + property_ids: PropertyDeclarationIdSet::default(), } } /// Create a block with a single declaration pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self { - let mut longhands = LonghandIdSet::new(); - if let PropertyDeclarationId::Longhand(id) = declaration.id() { - longhands.insert(id); - } + let mut property_ids = PropertyDeclarationIdSet::default(); + property_ids.insert(declaration.id()); + let mut declarations = ThinVec::with_capacity(1); + declarations.push(declaration); PropertyDeclarationBlock { - declarations: vec![declaration], + declarations, declarations_importance: SmallBitVec::from_elem(1, importance.important()), - longhands, + property_ids, } } @@ -311,23 +356,23 @@ impl PropertyDeclarationBlock { !self.declarations_importance.all_true() } - /// Returns whether this block contains a declaration of a given longhand. + /// Returns a `LonghandIdSet` representing the properties that are changed in + /// this block. #[inline] - pub fn contains(&self, id: LonghandId) -> bool { - self.longhands.contains(id) + pub fn longhands(&self) -> &LonghandIdSet { + &self.property_ids.longhands + } + + /// Returns whether this block contains a declaration of a given property id. + #[inline] + pub fn contains(&self, id: PropertyDeclarationId) -> bool { + self.property_ids.contains(id) } /// Returns whether this block contains any reset longhand. #[inline] pub fn contains_any_reset(&self) -> bool { - self.longhands.contains_any_reset() - } - - /// Returns a `LonghandIdSet` representing the properties that are changed in - /// this block. - #[inline] - pub fn longhands(&self) -> &LonghandIdSet { - &self.longhands + self.property_ids.longhands.contains_any_reset() } /// Get a declaration for a given property. @@ -339,12 +384,9 @@ impl PropertyDeclarationBlock { &self, property: PropertyDeclarationId, ) -> Option<(&PropertyDeclaration, Importance)> { - if let PropertyDeclarationId::Longhand(id) = property { - if !self.contains(id) { - return None; - } + if !self.contains(property) { + return None; } - self.declaration_importance_iter() .find(|(declaration, _)| declaration.id() == property) } @@ -443,16 +485,6 @@ impl PropertyDeclarationBlock { } } - /// Returns whether the property is definitely new for this declaration - /// block. It returns true when the declaration is a non-custom longhand - /// and it doesn't exist in the block, and returns false otherwise. - #[inline] - fn is_definitely_new(&self, decl: &PropertyDeclaration) -> bool { - decl.id() - .as_longhand() - .map_or(false, |id| !self.longhands.contains(id)) - } - /// Adds or overrides the declaration for a given property in this block. /// /// See the documentation of `push` to see what impact `source` has when the @@ -491,10 +523,11 @@ impl PropertyDeclarationBlock { /// /// This is only used for parsing and internal use. pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) -> bool { - if !self.is_definitely_new(&declaration) { + let id = declaration.id(); + if !self.property_ids.insert(id) { let mut index_to_remove = None; for (i, slot) in self.declarations.iter_mut().enumerate() { - if slot.id() != declaration.id() { + if slot.id() != id { continue; } @@ -519,9 +552,6 @@ impl PropertyDeclarationBlock { } } - if let PropertyDeclarationId::Longhand(id) = declaration.id() { - self.longhands.insert(id); - } self.declarations.push(declaration); self.declarations_importance.push(importance.important()); true @@ -544,7 +574,7 @@ impl PropertyDeclarationBlock { .all_shorthand .declarations() .any(|decl| { - self.is_definitely_new(&decl) || + !self.contains(decl.id()) || self.declarations .iter() .enumerate() @@ -565,7 +595,7 @@ impl PropertyDeclarationBlock { .declarations .iter() .map(|declaration| { - if self.is_definitely_new(declaration) { + if !self.contains(declaration.id()) { return DeclarationUpdate::Append; } let longhand_id = declaration.id().as_longhand(); @@ -640,11 +670,10 @@ impl PropertyDeclarationBlock { if !matches!(drain.all_shorthand, AllShorthand::NotSet) { debug_assert!(updates.updates.is_empty()); for decl in drain.all_shorthand.declarations() { - if self.is_definitely_new(&decl) { - let longhand_id = decl.id().as_longhand().unwrap(); + let id = decl.id(); + if self.property_ids.insert(id) { self.declarations.push(decl); self.declarations_importance.push(important); - self.longhands.insert(longhand_id); } else { let (idx, slot) = self .declarations @@ -711,9 +740,7 @@ impl PropertyDeclarationBlock { match *update { DeclarationUpdate::None => {}, DeclarationUpdate::Append | DeclarationUpdate::AppendAndRemove { .. } => { - if let Some(id) = decl.id().as_longhand() { - self.longhands.insert(id); - } + self.property_ids.insert(decl.id()); self.declarations.push(decl); self.declarations_importance.push(important); }, @@ -730,8 +757,8 @@ impl PropertyDeclarationBlock { /// `property`. #[inline] pub fn first_declaration_to_remove(&self, property: &PropertyId) -> Option { - if let Some(id) = property.longhand_id() { - if !self.longhands.contains(id) { + if let Err(longhand_or_custom) = property.as_shorthand() { + if !self.contains(longhand_or_custom) { return None; } } @@ -744,13 +771,8 @@ impl PropertyDeclarationBlock { /// Removes a given declaration at a given index. #[inline] fn remove_declaration_at(&mut self, i: usize) { - { - let id = self.declarations[i].id(); - if let PropertyDeclarationId::Longhand(id) = id { - self.longhands.remove(id); - } - self.declarations_importance.remove(i); - } + self.property_ids.remove(self.declarations[i].id()); + self.declarations_importance.remove(i); self.declarations.remove(i); } @@ -759,7 +781,7 @@ impl PropertyDeclarationBlock { pub fn clear(&mut self) { self.declarations_importance.clear(); self.declarations.clear(); - self.longhands.clear(); + self.property_ids.clear(); } /// @@ -858,17 +880,17 @@ impl PropertyDeclarationBlock { /// Convert AnimationValueMap to PropertyDeclarationBlock. pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self { let len = animation_value_map.len(); - let mut declarations = Vec::with_capacity(len); - let mut longhands = LonghandIdSet::new(); + let mut declarations = ThinVec::with_capacity(len); + let mut property_ids = PropertyDeclarationIdSet::default(); for (property, animation_value) in animation_value_map.iter() { - longhands.insert(*property); + property_ids.longhands.insert(*property); declarations.push(animation_value.uncompute()); } PropertyDeclarationBlock { declarations, - longhands, + property_ids, declarations_importance: SmallBitVec::from_elem(len, false), } } @@ -876,8 +898,8 @@ impl PropertyDeclarationBlock { /// Returns true if the declaration block has a CSSWideKeyword for the given /// property. pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool { - if let Some(id) = property.longhand_id() { - if !self.longhands.contains(id) { + if let Err(longhand_or_custom) = property.as_shorthand() { + if !self.property_ids.contains(longhand_or_custom) { return false; } } @@ -993,7 +1015,7 @@ impl PropertyDeclarationBlock { // If all properties that map to shorthand are not present // in longhands, continue with the steps labeled shorthand // loop. - if !self.longhands.contains_all(&longhands) { + if !self.property_ids.longhands.contains_all(&longhands) { continue; } @@ -1388,15 +1410,11 @@ fn report_one_css_error<'i>( debug_assert!(context.error_reporting_enabled()); fn all_properties_in_block(block: &PropertyDeclarationBlock, property: &PropertyId) -> bool { - match *property { - PropertyId::LonghandAlias(id, _) | PropertyId::Longhand(id) => block.contains(id), - PropertyId::ShorthandAlias(id, _) | PropertyId::Shorthand(id) => { - id.longhands().all(|longhand| block.contains(longhand)) - }, - // NOTE(emilio): We could do this, but it seems of limited utility, - // and it's linear on the size of the declaration block, so let's - // not. - PropertyId::Custom(..) => false, + match property.as_shorthand() { + Ok(id) => id + .longhands() + .all(|longhand| block.contains(PropertyDeclarationId::Longhand(longhand))), + Err(longhand_or_custom) => block.contains(longhand_or_custom), } } diff --git a/components/to_shmem/lib.rs b/components/to_shmem/lib.rs index 5a968c1283b..819ff8d6923 100644 --- a/components/to_shmem/lib.rs +++ b/components/to_shmem/lib.rs @@ -17,7 +17,6 @@ extern crate thin_vec; use std::alloc::Layout; #[cfg(debug_assertions)] use std::any::TypeId; -#[cfg(debug_assertions)] use std::collections::HashSet; use std::ffi::CString; use std::marker::PhantomData; @@ -426,6 +425,21 @@ impl ToShmem for Option { } } +impl ToShmem for HashSet +where + Self: Default, +{ + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> Result { + if !self.is_empty() { + return Err(format!( + "ToShmem failed for HashSet: We only support empty sets \ + (we don't expect custom properties in UA sheets, they're observable by content)", + )) + } + Ok(ManuallyDrop::new(Self::default())) + } +} + impl ToShmem for Arc { fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // Assert that we don't encounter any shared references to values we