Skip to content

Commit

Permalink
style: Make :host::part work in the same shadow tree as the part.
Browse files Browse the repository at this point in the history
  • Loading branch information
emilio committed Apr 16, 2020
1 parent 257b96c commit 846996a
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 74 deletions.
27 changes: 15 additions & 12 deletions components/selectors/matching.rs
Expand Up @@ -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.
Expand Down
159 changes: 97 additions & 62 deletions components/style/rule_collector.rs
Expand Up @@ -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.
///
Expand All @@ -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>
Expand Down Expand Up @@ -134,7 +130,33 @@ 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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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.
Expand All @@ -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) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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();
}
}

0 comments on commit 846996a

Please sign in to comment.