mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
style: Factor out adding a rule in CascadeData::add_rule
This shouldn't have any behavior change, but is necessary because for cascade layers we are going to need to handle the child rules / sheets ourselves, in order to handle nested layers properly. Differential Revision: https://phabricator.services.mozilla.com/D124334
This commit is contained in:
parent
9822db5d3c
commit
9976f9a589
1 changed files with 183 additions and 157 deletions
|
@ -2125,6 +2125,179 @@ impl CascadeData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add_rule<S>(
|
||||||
|
&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 <slot> 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
|
// Returns Err(..) to signify OOM
|
||||||
fn add_stylesheet<S>(
|
fn add_stylesheet<S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -2143,169 +2316,22 @@ impl CascadeData {
|
||||||
}
|
}
|
||||||
|
|
||||||
let contents = stylesheet.contents();
|
let contents = stylesheet.contents();
|
||||||
let origin = contents.origin;
|
|
||||||
|
|
||||||
if rebuild_kind.should_rebuild_invalidation() {
|
if rebuild_kind.should_rebuild_invalidation() {
|
||||||
self.effective_media_query_results.saw_effective(contents);
|
self.effective_media_query_results.saw_effective(contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for rule in stylesheet.effective_rules(device, guard) {
|
for rule in stylesheet.effective_rules(device, guard) {
|
||||||
match *rule {
|
self.add_rule(
|
||||||
CssRule::Style(ref locked) => {
|
rule,
|
||||||
let style_rule = locked.read_with(&guard);
|
device,
|
||||||
self.num_declarations += style_rule.block.read_with(&guard).len();
|
quirks_mode,
|
||||||
for selector in &style_rule.selectors.0 {
|
stylesheet,
|
||||||
self.num_selectors += 1;
|
guard,
|
||||||
|
rebuild_kind,
|
||||||
let pseudo_element = selector.pseudo_element();
|
precomputed_pseudo_element_decls.as_deref_mut(),
|
||||||
|
)?;
|
||||||
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 <slot> 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(())
|
Ok(())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue