diff --git a/components/style/stylist.rs b/components/style/stylist.rs index ef3d43ab737..677ba49729f 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -2125,6 +2125,179 @@ impl CascadeData { } } + #[inline] + fn add_rule( + &mut self, + rule: &CssRule, + _device: &Device, + quirks_mode: QuirksMode, + stylesheet: &S, + guard: &SharedRwLockReadGuard, + rebuild_kind: SheetRebuildKind, + mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>, + ) -> Result<(), FailedAllocationError> + where + S: StylesheetInDocument + 'static, + { + match *rule { + CssRule::Style(ref locked) => { + let style_rule = locked.read_with(&guard); + self.num_declarations += style_rule.block.read_with(&guard).len(); + for selector in &style_rule.selectors.0 { + self.num_selectors += 1; + + let pseudo_element = selector.pseudo_element(); + + if let Some(pseudo) = pseudo_element { + if pseudo.is_precomputed() { + debug_assert!(selector.is_universal()); + debug_assert_eq!(stylesheet.contents().origin, Origin::UserAgent); + + precomputed_pseudo_element_decls + .as_mut() + .expect("Expected precomputed declarations for the UA level") + .get_or_insert_with(pseudo, Vec::new) + .push(ApplicableDeclarationBlock::new( + StyleSource::from_rule(locked.clone()), + self.rules_source_order, + CascadeLevel::UANormal, + selector.specificity(), + )); + continue; + } + if pseudo.is_unknown_webkit_pseudo_element() { + continue; + } + } + + let hashes = AncestorHashes::new(&selector, quirks_mode); + + let rule = Rule::new( + selector.clone(), + hashes, + locked.clone(), + self.rules_source_order, + ); + + if rebuild_kind.should_rebuild_invalidation() { + self.invalidation_map.note_selector(selector, quirks_mode)?; + let mut needs_revalidation = false; + let mut visitor = StylistSelectorVisitor { + needs_revalidation: &mut needs_revalidation, + passed_rightmost_selector: false, + attribute_dependencies: &mut self.attribute_dependencies, + state_dependencies: &mut self.state_dependencies, + document_state_dependencies: &mut self.document_state_dependencies, + mapped_ids: &mut self.mapped_ids, + }; + + rule.selector.visit(&mut visitor); + + if needs_revalidation { + self.selectors_for_cache_revalidation.insert( + RevalidationSelectorAndHashes::new( + rule.selector.clone(), + rule.hashes.clone(), + ), + quirks_mode, + )?; + } + } + + // Part is special, since given it doesn't have any + // selectors inside, it's not worth using a whole + // SelectorMap for it. + if let Some(parts) = selector.parts() { + // ::part() has all semantics, so we just need to + // put any of them in the selector map. + // + // We choose the last one quite arbitrarily, + // expecting it's slightly more likely to be more + // specific. + self.part_rules + .get_or_insert_with(|| Box::new(Default::default())) + .for_insertion(pseudo_element) + .try_entry(parts.last().unwrap().clone().0)? + .or_insert_with(SmallVec::new) + .try_push(rule)?; + } else { + // NOTE(emilio): It's fine to look at :host and then at + // ::slotted(..), since :host::slotted(..) could never + // possibly match, as is not a valid shadow host. + let rules = + if selector.is_featureless_host_selector_or_pseudo_element() { + self.host_rules + .get_or_insert_with(|| Box::new(Default::default())) + } else if selector.is_slotted() { + self.slotted_rules + .get_or_insert_with(|| Box::new(Default::default())) + } else { + &mut self.normal_rules + } + .for_insertion(pseudo_element); + rules.insert(rule, quirks_mode)?; + } + } + self.rules_source_order += 1; + }, + CssRule::Import(ref lock) => { + if rebuild_kind.should_rebuild_invalidation() { + let import_rule = lock.read_with(guard); + self.effective_media_query_results + .saw_effective(import_rule); + } + + // NOTE: effective_rules visits the inner stylesheet if + // appropriate. + }, + CssRule::Media(ref lock) => { + if rebuild_kind.should_rebuild_invalidation() { + let media_rule = lock.read_with(guard); + self.effective_media_query_results.saw_effective(media_rule); + } + }, + CssRule::Keyframes(ref keyframes_rule) => { + let keyframes_rule = keyframes_rule.read_with(guard); + debug!("Found valid keyframes rule: {:?}", *keyframes_rule); + + // Don't let a prefixed keyframes animation override a non-prefixed one. + let needs_insertion = keyframes_rule.vendor_prefix.is_none() || + self.animations + .get(keyframes_rule.name.as_atom()) + .map_or(true, |rule| rule.vendor_prefix.is_some()); + if needs_insertion { + let animation = KeyframesAnimation::from_keyframes( + &keyframes_rule.keyframes, + keyframes_rule.vendor_prefix.clone(), + guard, + ); + debug!("Found valid keyframe animation: {:?}", animation); + self.animations + .try_insert(keyframes_rule.name.as_atom().clone(), animation)?; + } + }, + #[cfg(feature = "gecko")] + CssRule::FontFace(ref rule) => { + self.extra_data.add_font_face(rule); + }, + #[cfg(feature = "gecko")] + CssRule::FontFeatureValues(ref rule) => { + self.extra_data.add_font_feature_values(rule); + }, + #[cfg(feature = "gecko")] + CssRule::CounterStyle(ref rule) => { + self.extra_data.add_counter_style(guard, rule); + }, + #[cfg(feature = "gecko")] + CssRule::Page(ref rule) => { + self.extra_data.add_page(rule); + }, + // We don't care about any other rule. + _ => {}, + } + Ok(()) + } + // Returns Err(..) to signify OOM fn add_stylesheet( &mut self, @@ -2143,169 +2316,22 @@ impl CascadeData { } let contents = stylesheet.contents(); - let origin = contents.origin; if rebuild_kind.should_rebuild_invalidation() { self.effective_media_query_results.saw_effective(contents); } + for rule in stylesheet.effective_rules(device, guard) { - match *rule { - CssRule::Style(ref locked) => { - let style_rule = locked.read_with(&guard); - self.num_declarations += style_rule.block.read_with(&guard).len(); - for selector in &style_rule.selectors.0 { - self.num_selectors += 1; - - let pseudo_element = selector.pseudo_element(); - - if let Some(pseudo) = pseudo_element { - if pseudo.is_precomputed() { - debug_assert!(selector.is_universal()); - debug_assert!(matches!(origin, Origin::UserAgent)); - - precomputed_pseudo_element_decls - .as_mut() - .expect("Expected precomputed declarations for the UA level") - .get_or_insert_with(pseudo, Vec::new) - .push(ApplicableDeclarationBlock::new( - StyleSource::from_rule(locked.clone()), - self.rules_source_order, - CascadeLevel::UANormal, - selector.specificity(), - )); - continue; - } - if pseudo.is_unknown_webkit_pseudo_element() { - continue; - } - } - - let hashes = AncestorHashes::new(&selector, quirks_mode); - - let rule = Rule::new( - selector.clone(), - hashes, - locked.clone(), - self.rules_source_order, - ); - - if rebuild_kind.should_rebuild_invalidation() { - self.invalidation_map.note_selector(selector, quirks_mode)?; - let mut needs_revalidation = false; - let mut visitor = StylistSelectorVisitor { - needs_revalidation: &mut needs_revalidation, - passed_rightmost_selector: false, - attribute_dependencies: &mut self.attribute_dependencies, - state_dependencies: &mut self.state_dependencies, - document_state_dependencies: &mut self.document_state_dependencies, - mapped_ids: &mut self.mapped_ids, - }; - - rule.selector.visit(&mut visitor); - - if needs_revalidation { - self.selectors_for_cache_revalidation.insert( - RevalidationSelectorAndHashes::new( - rule.selector.clone(), - rule.hashes.clone(), - ), - quirks_mode, - )?; - } - } - - // Part is special, since given it doesn't have any - // selectors inside, it's not worth using a whole - // SelectorMap for it. - if let Some(parts) = selector.parts() { - // ::part() has all semantics, so we just need to - // put any of them in the selector map. - // - // We choose the last one quite arbitrarily, - // expecting it's slightly more likely to be more - // specific. - self.part_rules - .get_or_insert_with(|| Box::new(Default::default())) - .for_insertion(pseudo_element) - .try_entry(parts.last().unwrap().clone().0)? - .or_insert_with(SmallVec::new) - .try_push(rule)?; - } else { - // NOTE(emilio): It's fine to look at :host and then at - // ::slotted(..), since :host::slotted(..) could never - // possibly match, as is not a valid shadow host. - let rules = - if selector.is_featureless_host_selector_or_pseudo_element() { - self.host_rules - .get_or_insert_with(|| Box::new(Default::default())) - } else if selector.is_slotted() { - self.slotted_rules - .get_or_insert_with(|| Box::new(Default::default())) - } else { - &mut self.normal_rules - } - .for_insertion(pseudo_element); - rules.insert(rule, quirks_mode)?; - } - } - self.rules_source_order += 1; - }, - CssRule::Import(ref lock) => { - if rebuild_kind.should_rebuild_invalidation() { - let import_rule = lock.read_with(guard); - self.effective_media_query_results - .saw_effective(import_rule); - } - - // NOTE: effective_rules visits the inner stylesheet if - // appropriate. - }, - CssRule::Media(ref lock) => { - if rebuild_kind.should_rebuild_invalidation() { - let media_rule = lock.read_with(guard); - self.effective_media_query_results.saw_effective(media_rule); - } - }, - CssRule::Keyframes(ref keyframes_rule) => { - let keyframes_rule = keyframes_rule.read_with(guard); - debug!("Found valid keyframes rule: {:?}", *keyframes_rule); - - // Don't let a prefixed keyframes animation override a non-prefixed one. - let needs_insertion = keyframes_rule.vendor_prefix.is_none() || - self.animations - .get(keyframes_rule.name.as_atom()) - .map_or(true, |rule| rule.vendor_prefix.is_some()); - if needs_insertion { - let animation = KeyframesAnimation::from_keyframes( - &keyframes_rule.keyframes, - keyframes_rule.vendor_prefix.clone(), - guard, - ); - debug!("Found valid keyframe animation: {:?}", animation); - self.animations - .try_insert(keyframes_rule.name.as_atom().clone(), animation)?; - } - }, - #[cfg(feature = "gecko")] - CssRule::FontFace(ref rule) => { - self.extra_data.add_font_face(rule); - }, - #[cfg(feature = "gecko")] - CssRule::FontFeatureValues(ref rule) => { - self.extra_data.add_font_feature_values(rule); - }, - #[cfg(feature = "gecko")] - CssRule::CounterStyle(ref rule) => { - self.extra_data.add_counter_style(guard, rule); - }, - #[cfg(feature = "gecko")] - CssRule::Page(ref rule) => { - self.extra_data.add_page(rule); - }, - // We don't care about any other rule. - _ => {}, - } + self.add_rule( + rule, + device, + quirks_mode, + stylesheet, + guard, + rebuild_kind, + precomputed_pseudo_element_decls.as_deref_mut(), + )?; } Ok(())