mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
style: Make :host::part work in the same shadow tree as the part.
Differential Revision: https://phabricator.services.mozilla.com/D68249
This commit is contained in:
parent
257b96c549
commit
846996ae7e
2 changed files with 112 additions and 74 deletions
|
@ -676,19 +676,22 @@ where
|
|||
None => return false,
|
||||
};
|
||||
|
||||
loop {
|
||||
let outer_host = host.containing_shadow_host();
|
||||
if outer_host.as_ref().map(|h| h.opaque()) == context.shared.current_host {
|
||||
break;
|
||||
let current_host = context.shared.current_host;
|
||||
if current_host != Some(host.opaque()) {
|
||||
loop {
|
||||
let outer_host = host.containing_shadow_host();
|
||||
if outer_host.as_ref().map(|h| h.opaque()) == current_host {
|
||||
break;
|
||||
}
|
||||
let outer_host = match outer_host {
|
||||
Some(h) => h,
|
||||
None => return false,
|
||||
};
|
||||
// TODO(emilio): if worth it, we could early return if
|
||||
// host doesn't have the exportparts attribute.
|
||||
hosts.push(host);
|
||||
host = outer_host;
|
||||
}
|
||||
let outer_host = match outer_host {
|
||||
Some(h) => h,
|
||||
None => return false,
|
||||
};
|
||||
// TODO(emilio): if worth it, we could early return if
|
||||
// host doesn't have the exportparts attribute.
|
||||
hosts.push(host);
|
||||
host = outer_host;
|
||||
}
|
||||
|
||||
// Translate the part into the right scope.
|
||||
|
|
|
@ -55,11 +55,6 @@ pub fn containing_shadow_ignoring_svg_use<E: TElement>(
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_rules_from(rules: &mut ApplicableDeclarationList, start: usize) {
|
||||
rules[start..].sort_unstable_by_key(|block| (block.specificity, block.source_order()));
|
||||
}
|
||||
|
||||
/// An object that we use with all the intermediate state needed for the
|
||||
/// cascade.
|
||||
///
|
||||
|
@ -82,6 +77,7 @@ where
|
|||
flags_setter: &'a mut F,
|
||||
matches_user_and_author_rules: bool,
|
||||
matches_document_author_rules: bool,
|
||||
in_sort_scope: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F>
|
||||
|
@ -134,9 +130,35 @@ where
|
|||
rules,
|
||||
matches_user_and_author_rules,
|
||||
matches_document_author_rules: matches_user_and_author_rules,
|
||||
in_sort_scope: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the state necessary to collect rules from a given DOM tree
|
||||
/// (either the document tree, or a shadow tree).
|
||||
///
|
||||
/// All rules in the same tree need to be matched together, and this
|
||||
/// function takes care of sorting them by specificity and source order.
|
||||
#[inline]
|
||||
fn in_tree(&mut self, host: Option<E>, f: impl FnOnce(&mut Self)) {
|
||||
debug_assert!(!self.in_sort_scope, "Nested sorting makes no sense");
|
||||
let start = self.rules.len();
|
||||
self.in_sort_scope = true;
|
||||
let old_host = self.context.current_host.take();
|
||||
self.context.current_host = host.map(|e| e.opaque());
|
||||
f(self);
|
||||
if start != self.rules.len() {
|
||||
self.rules[start..].sort_unstable_by_key(|block| (block.specificity, block.source_order()));
|
||||
}
|
||||
self.context.current_host = old_host;
|
||||
self.in_sort_scope = false;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn in_shadow_tree(&mut self, host: E, f: impl FnOnce(&mut Self)) {
|
||||
self.in_tree(Some(host), f);
|
||||
}
|
||||
|
||||
fn collect_stylist_rules(&mut self, origin: Origin) {
|
||||
let cascade_level = match origin {
|
||||
Origin::UserAgent => CascadeLevel::UANormal,
|
||||
|
@ -150,7 +172,9 @@ where
|
|||
None => return,
|
||||
};
|
||||
|
||||
self.collect_rules_internal(None, map, cascade_level);
|
||||
self.in_tree(None, |collector| {
|
||||
collector.collect_rules_in_map(map, cascade_level);
|
||||
});
|
||||
}
|
||||
|
||||
fn collect_user_agent_rules(&mut self) {
|
||||
|
@ -189,39 +213,38 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_rules_in_shadow_tree(
|
||||
#[inline]
|
||||
fn collect_rules_in_list(
|
||||
&mut self,
|
||||
shadow_host: E,
|
||||
map: &SelectorMap<Rule>,
|
||||
part_rules: &[Rule],
|
||||
cascade_level: CascadeLevel,
|
||||
) {
|
||||
debug_assert!(shadow_host.shadow_root().is_some());
|
||||
self.collect_rules_internal(Some(shadow_host), map, cascade_level);
|
||||
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||
SelectorMap::get_matching_rules(
|
||||
self.element,
|
||||
part_rules,
|
||||
&mut self.rules,
|
||||
&mut self.context,
|
||||
&mut self.flags_setter,
|
||||
cascade_level,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_rules_internal(
|
||||
fn collect_rules_in_map(
|
||||
&mut self,
|
||||
shadow_host: Option<E>,
|
||||
map: &SelectorMap<Rule>,
|
||||
cascade_level: CascadeLevel,
|
||||
) {
|
||||
let element = self.element;
|
||||
let rule_hash_target = self.rule_hash_target;
|
||||
let rules = &mut self.rules;
|
||||
let flags_setter = &mut self.flags_setter;
|
||||
let start = rules.len();
|
||||
self.context.with_shadow_host(shadow_host, |context| {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
rules,
|
||||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
);
|
||||
});
|
||||
sort_rules_from(rules, start);
|
||||
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||
map.get_all_matching_rules(
|
||||
self.element,
|
||||
self.rule_hash_target,
|
||||
&mut self.rules,
|
||||
&mut self.context,
|
||||
&mut self.flags_setter,
|
||||
cascade_level,
|
||||
);
|
||||
}
|
||||
|
||||
/// Collects the rules for the ::slotted pseudo-element and the :host
|
||||
|
@ -258,17 +281,16 @@ where
|
|||
None => continue,
|
||||
};
|
||||
|
||||
self.collect_rules_in_shadow_tree(
|
||||
shadow.host(),
|
||||
slotted_rules,
|
||||
CascadeLevel::AuthorNormal {
|
||||
self.in_shadow_tree(shadow.host(), |collector| {
|
||||
let cascade_level = CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
},
|
||||
);
|
||||
};
|
||||
collector.collect_rules_in_map(slotted_rules, cascade_level);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_normal_rules_from_containing_shadow_tree(&mut self) {
|
||||
fn collect_rules_from_containing_shadow_tree(&mut self) {
|
||||
if !self.matches_user_and_author_rules {
|
||||
return;
|
||||
}
|
||||
|
@ -281,11 +303,34 @@ where
|
|||
|
||||
self.matches_document_author_rules = false;
|
||||
|
||||
let cascade_data = containing_shadow.style_data();
|
||||
let host = containing_shadow.host();
|
||||
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) {
|
||||
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::same_tree_author_normal());
|
||||
}
|
||||
let cascade_data = match containing_shadow.style_data() {
|
||||
Some(c) => c,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let cascade_level = CascadeLevel::same_tree_author_normal();
|
||||
self.in_shadow_tree(containing_shadow.host(), |collector| {
|
||||
if let Some(map) = cascade_data.normal_rules(collector.pseudo_element) {
|
||||
collector.collect_rules_in_map(map, cascade_level);
|
||||
}
|
||||
|
||||
// Collect rules from :host::part() and such
|
||||
let hash_target = collector.rule_hash_target;
|
||||
if !hash_target.has_part_attr() {
|
||||
return;
|
||||
}
|
||||
|
||||
let part_rules = match cascade_data.part_rules(collector.pseudo_element) {
|
||||
Some(p) => p,
|
||||
None => return,
|
||||
};
|
||||
|
||||
hash_target.each_part(|part| {
|
||||
if let Some(part_rules) = part_rules.get(part) {
|
||||
collector.collect_rules_in_list(part_rules, cascade_level);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Collects the rules for the :host pseudo-class.
|
||||
|
@ -311,13 +356,12 @@ where
|
|||
};
|
||||
|
||||
let rule_hash_target = self.rule_hash_target;
|
||||
self.collect_rules_in_shadow_tree(
|
||||
rule_hash_target,
|
||||
host_rules,
|
||||
CascadeLevel::AuthorNormal {
|
||||
self.in_shadow_tree(rule_hash_target, |collector| {
|
||||
let cascade_level = CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
},
|
||||
);
|
||||
};
|
||||
collector.collect_rules_in_map(host_rules, cascade_level);
|
||||
});
|
||||
}
|
||||
|
||||
fn collect_document_author_rules(&mut self) {
|
||||
|
@ -328,7 +372,7 @@ where
|
|||
self.collect_stylist_rules(Origin::Author);
|
||||
}
|
||||
|
||||
fn collect_part_rules(&mut self) {
|
||||
fn collect_part_rules_from_outer_trees(&mut self) {
|
||||
if !self.rule_hash_target.has_part_attr() {
|
||||
return;
|
||||
}
|
||||
|
@ -363,28 +407,19 @@ where
|
|||
|
||||
if let Some(part_rules) = part_rules {
|
||||
let containing_host = outer_shadow.map(|s| s.host());
|
||||
let element = self.element;
|
||||
let rules = &mut self.rules;
|
||||
let flags_setter = &mut self.flags_setter;
|
||||
let cascade_level = CascadeLevel::AuthorNormal {
|
||||
shadow_cascade_order,
|
||||
};
|
||||
let start = rules.len();
|
||||
self.context.with_shadow_host(containing_host, |context| {
|
||||
self.in_tree(containing_host, |collector| {
|
||||
for p in &parts {
|
||||
if let Some(part_rules) = part_rules.get(p) {
|
||||
SelectorMap::get_matching_rules(
|
||||
element,
|
||||
&part_rules,
|
||||
rules,
|
||||
context,
|
||||
flags_setter,
|
||||
collector.collect_rules_in_list(
|
||||
part_rules,
|
||||
cascade_level,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
sort_rules_from(rules, start);
|
||||
shadow_cascade_order.inc();
|
||||
}
|
||||
|
||||
|
@ -460,10 +495,10 @@ where
|
|||
return;
|
||||
}
|
||||
self.collect_host_and_slotted_rules();
|
||||
self.collect_normal_rules_from_containing_shadow_tree();
|
||||
self.collect_rules_from_containing_shadow_tree();
|
||||
self.collect_document_author_rules();
|
||||
self.collect_style_attribute();
|
||||
self.collect_part_rules();
|
||||
self.collect_part_rules_from_outer_trees();
|
||||
self.collect_animation_rules();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue