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,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
let current_host = context.shared.current_host;
|
||||||
let outer_host = host.containing_shadow_host();
|
if current_host != Some(host.opaque()) {
|
||||||
if outer_host.as_ref().map(|h| h.opaque()) == context.shared.current_host {
|
loop {
|
||||||
break;
|
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.
|
// 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
|
/// An object that we use with all the intermediate state needed for the
|
||||||
/// cascade.
|
/// cascade.
|
||||||
///
|
///
|
||||||
|
@ -82,6 +77,7 @@ where
|
||||||
flags_setter: &'a mut F,
|
flags_setter: &'a mut F,
|
||||||
matches_user_and_author_rules: bool,
|
matches_user_and_author_rules: bool,
|
||||||
matches_document_author_rules: bool,
|
matches_document_author_rules: bool,
|
||||||
|
in_sort_scope: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F>
|
impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F>
|
||||||
|
@ -134,9 +130,35 @@ where
|
||||||
rules,
|
rules,
|
||||||
matches_user_and_author_rules,
|
matches_user_and_author_rules,
|
||||||
matches_document_author_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) {
|
fn collect_stylist_rules(&mut self, origin: Origin) {
|
||||||
let cascade_level = match origin {
|
let cascade_level = match origin {
|
||||||
Origin::UserAgent => CascadeLevel::UANormal,
|
Origin::UserAgent => CascadeLevel::UANormal,
|
||||||
|
@ -150,7 +172,9 @@ where
|
||||||
None => return,
|
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) {
|
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,
|
&mut self,
|
||||||
shadow_host: E,
|
part_rules: &[Rule],
|
||||||
map: &SelectorMap<Rule>,
|
|
||||||
cascade_level: CascadeLevel,
|
cascade_level: CascadeLevel,
|
||||||
) {
|
) {
|
||||||
debug_assert!(shadow_host.shadow_root().is_some());
|
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||||
self.collect_rules_internal(Some(shadow_host), map, cascade_level);
|
SelectorMap::get_matching_rules(
|
||||||
|
self.element,
|
||||||
|
part_rules,
|
||||||
|
&mut self.rules,
|
||||||
|
&mut self.context,
|
||||||
|
&mut self.flags_setter,
|
||||||
|
cascade_level,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn collect_rules_internal(
|
fn collect_rules_in_map(
|
||||||
&mut self,
|
&mut self,
|
||||||
shadow_host: Option<E>,
|
|
||||||
map: &SelectorMap<Rule>,
|
map: &SelectorMap<Rule>,
|
||||||
cascade_level: CascadeLevel,
|
cascade_level: CascadeLevel,
|
||||||
) {
|
) {
|
||||||
let element = self.element;
|
debug_assert!(self.in_sort_scope, "Rules gotta be sorted");
|
||||||
let rule_hash_target = self.rule_hash_target;
|
map.get_all_matching_rules(
|
||||||
let rules = &mut self.rules;
|
self.element,
|
||||||
let flags_setter = &mut self.flags_setter;
|
self.rule_hash_target,
|
||||||
let start = rules.len();
|
&mut self.rules,
|
||||||
self.context.with_shadow_host(shadow_host, |context| {
|
&mut self.context,
|
||||||
map.get_all_matching_rules(
|
&mut self.flags_setter,
|
||||||
element,
|
cascade_level,
|
||||||
rule_hash_target,
|
);
|
||||||
rules,
|
|
||||||
context,
|
|
||||||
flags_setter,
|
|
||||||
cascade_level,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
sort_rules_from(rules, start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects the rules for the ::slotted pseudo-element and the :host
|
/// Collects the rules for the ::slotted pseudo-element and the :host
|
||||||
|
@ -258,17 +281,16 @@ where
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.collect_rules_in_shadow_tree(
|
self.in_shadow_tree(shadow.host(), |collector| {
|
||||||
shadow.host(),
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
slotted_rules,
|
|
||||||
CascadeLevel::AuthorNormal {
|
|
||||||
shadow_cascade_order,
|
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 {
|
if !self.matches_user_and_author_rules {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -281,11 +303,34 @@ where
|
||||||
|
|
||||||
self.matches_document_author_rules = false;
|
self.matches_document_author_rules = false;
|
||||||
|
|
||||||
let cascade_data = containing_shadow.style_data();
|
let cascade_data = match containing_shadow.style_data() {
|
||||||
let host = containing_shadow.host();
|
Some(c) => c,
|
||||||
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) {
|
None => return,
|
||||||
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::same_tree_author_normal());
|
};
|
||||||
}
|
|
||||||
|
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.
|
/// Collects the rules for the :host pseudo-class.
|
||||||
|
@ -311,13 +356,12 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let rule_hash_target = self.rule_hash_target;
|
let rule_hash_target = self.rule_hash_target;
|
||||||
self.collect_rules_in_shadow_tree(
|
self.in_shadow_tree(rule_hash_target, |collector| {
|
||||||
rule_hash_target,
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
host_rules,
|
|
||||||
CascadeLevel::AuthorNormal {
|
|
||||||
shadow_cascade_order,
|
shadow_cascade_order,
|
||||||
},
|
};
|
||||||
);
|
collector.collect_rules_in_map(host_rules, cascade_level);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_document_author_rules(&mut self) {
|
fn collect_document_author_rules(&mut self) {
|
||||||
|
@ -328,7 +372,7 @@ where
|
||||||
self.collect_stylist_rules(Origin::Author);
|
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() {
|
if !self.rule_hash_target.has_part_attr() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -363,28 +407,19 @@ where
|
||||||
|
|
||||||
if let Some(part_rules) = part_rules {
|
if let Some(part_rules) = part_rules {
|
||||||
let containing_host = outer_shadow.map(|s| s.host());
|
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 {
|
let cascade_level = CascadeLevel::AuthorNormal {
|
||||||
shadow_cascade_order,
|
shadow_cascade_order,
|
||||||
};
|
};
|
||||||
let start = rules.len();
|
self.in_tree(containing_host, |collector| {
|
||||||
self.context.with_shadow_host(containing_host, |context| {
|
|
||||||
for p in &parts {
|
for p in &parts {
|
||||||
if let Some(part_rules) = part_rules.get(p) {
|
if let Some(part_rules) = part_rules.get(p) {
|
||||||
SelectorMap::get_matching_rules(
|
collector.collect_rules_in_list(
|
||||||
element,
|
part_rules,
|
||||||
&part_rules,
|
|
||||||
rules,
|
|
||||||
context,
|
|
||||||
flags_setter,
|
|
||||||
cascade_level,
|
cascade_level,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sort_rules_from(rules, start);
|
|
||||||
shadow_cascade_order.inc();
|
shadow_cascade_order.inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,10 +495,10 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.collect_host_and_slotted_rules();
|
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_document_author_rules();
|
||||||
self.collect_style_attribute();
|
self.collect_style_attribute();
|
||||||
self.collect_part_rules();
|
self.collect_part_rules_from_outer_trees();
|
||||||
self.collect_animation_rules();
|
self.collect_animation_rules();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue