From 7139a4185a583f190cab1e9e8fb056cd6149a815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 11 Jun 2019 17:42:41 +0000 Subject: [PATCH] style: Add code to make part rules affect the style of the elements. I still haven't implemented each_part(), so this will do nothing yet. The cascade order stuff is fishy, I know, and I'll fix in a followup if it's fine with you. I moved the sorting of the rules to rule_collector, since it seemed to me it was better that way that duplicating the code, and those SelectorMap functions only have a single caller anyway. Differential Revision: https://phabricator.services.mozilla.com/D32647 --- components/selectors/context.rs | 4 +- components/style/dom.rs | 10 ++++ components/style/gecko/wrapper.rs | 10 ++-- components/style/rule_collector.rs | 91 ++++++++++++++++++++++++++---- components/style/selector_map.rs | 10 +--- components/style/stylist.rs | 2 +- 6 files changed, 100 insertions(+), 27 deletions(-) diff --git a/components/selectors/context.rs b/components/selectors/context.rs index 3686513e79d..d159891ff02 100644 --- a/components/selectors/context.rs +++ b/components/selectors/context.rs @@ -279,13 +279,13 @@ where /// Runs F with a given shadow host which is the root of the tree whose /// rules we're matching. #[inline] - pub fn with_shadow_host(&mut self, host: E, f: F) -> R + pub fn with_shadow_host(&mut self, host: Option, f: F) -> R where E: Element, F: FnOnce(&mut Self) -> R, { let original_host = self.current_host.take(); - self.current_host = Some(host.opaque()); + self.current_host = host.map(|h| h.opaque()); let result = f(self); self.current_host = original_host; result diff --git a/components/style/dom.rs b/components/style/dom.rs index 0a743c60207..0e68e55c47f 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -520,6 +520,9 @@ pub trait TElement: /// Whether this element has an attribute with a given namespace. fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool; + /// Returns whether this element has a `part` attribute. + fn has_part_attr(&self) -> bool; + /// The ID for this element. fn id(&self) -> Option<&WeakAtom>; @@ -528,6 +531,13 @@ pub trait TElement: where F: FnMut(&Atom); + /// Internal iterator for the part names of this element. + fn each_part(&self, _callback: F) + where + F: FnMut(&Atom) + { + } + /// Whether a given element may generate a pseudo-element. /// /// This is useful to avoid computing, for example, pseudo styles for diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 70eaa552ed5..17c1cfaf35d 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -626,11 +626,6 @@ impl<'le> GeckoElement<'le> { } } - #[inline] - fn has_part_attr(&self) -> bool { - self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasPart) - } - #[inline] fn may_have_anonymous_children(&self) -> bool { self.as_node() @@ -1353,6 +1348,11 @@ impl<'le> TElement for GeckoElement<'le> { unsafe { bindings::Gecko_HasAttr(self.0, namespace.0.as_ptr(), attr.as_ptr()) } } + #[inline] + fn has_part_attr(&self) -> bool { + self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementHasPart) + } + // FIXME(emilio): we should probably just return a reference to the Atom. #[inline] fn id(&self) -> Option<&WeakAtom> { diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index 360b8101ef1..dcd39c2b36c 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -54,6 +54,11 @@ pub fn containing_shadow_ignoring_svg_use( } } +#[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. /// @@ -146,15 +151,7 @@ where None => return, }; - map.get_all_matching_rules( - self.element, - self.rule_hash_target, - self.rules, - self.context, - self.flags_setter, - cascade_level, - 0, - ); + self.collect_rules_internal(None, map, cascade_level); } fn collect_user_agent_rules(&mut self) { @@ -200,11 +197,23 @@ where cascade_level: CascadeLevel, ) { debug_assert!(shadow_host.shadow_root().is_some()); + self.collect_rules_internal(Some(shadow_host), map, cascade_level); + self.shadow_cascade_order += 1; + } + + #[inline] + fn collect_rules_internal( + &mut self, + shadow_host: Option, + map: &SelectorMap, + 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 shadow_cascade_order = self.shadow_cascade_order; + let start = rules.len(); self.context.with_shadow_host(shadow_host, |context| { map.get_all_matching_rules( element, @@ -216,7 +225,7 @@ where shadow_cascade_order, ); }); - self.shadow_cascade_order += 1; + sort_rules_from(rules, start); } /// Collects the rules for the ::slotted pseudo-element. @@ -310,6 +319,67 @@ where self.collect_stylist_rules(Origin::Author); } + fn collect_part_rules(&mut self) { + if !self.rule_hash_target.has_part_attr() { + return; + } + + let shadow = match self.rule_hash_target.containing_shadow() { + Some(s) => s, + None => return, + }; + + let host = shadow.host(); + let containing_shadow = host.containing_shadow(); + let part_rules = match containing_shadow { + Some(shadow) => { + shadow + .style_data() + .and_then(|data| data.part_rules(self.pseudo_element)) + }, + None => { + self.stylist + .cascade_data() + .borrow_for_origin(Origin::Author) + .part_rules(self.pseudo_element) + } + }; + + // TODO(emilio): SameTreeAuthorNormal is a bit of a lie here, we may + // need an OuterTreeAuthorNormal cascade level or such, and change the + // cascade order, if we allow to forward parts to even outer trees. + // + // Though the current thing kinda works because we apply them after + // the outer tree, so as long as we don't allow forwarding we're + // good. + if let Some(part_rules) = part_rules { + let containing_host = containing_shadow.map(|s| s.host()); + 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 shadow_cascade_order = self.shadow_cascade_order; + let cascade_level = CascadeLevel::SameTreeAuthorNormal; + let start = rules.len(); + self.context.with_shadow_host(containing_host, |context| { + rule_hash_target.each_part(|p| { + if let Some(part_rules) = part_rules.get(p) { + SelectorMap::get_matching_rules( + element, + &part_rules, + rules, + context, + flags_setter, + cascade_level, + shadow_cascade_order, + ); + } + }); + }); + sort_rules_from(rules, start); + } + } + fn collect_style_attribute_and_animation_rules(&mut self) { if let Some(sa) = self.style_attribute { self.rules @@ -368,6 +438,7 @@ where self.collect_slotted_rules(); self.collect_normal_rules_from_containing_shadow_tree(); self.collect_document_author_rules(); + self.collect_part_rules(); self.collect_style_attribute_and_animation_rules(); } } diff --git a/components/style/selector_map.rs b/components/style/selector_map.rs index afae5450182..a1ef9d0c273 100644 --- a/components/style/selector_map.rs +++ b/components/style/selector_map.rs @@ -182,10 +182,6 @@ impl SelectorMap { let quirks_mode = context.quirks_mode(); - // At the end, we're going to sort the rules that we added, so remember - // where we began. - let init_len = matching_rules_list.len(); - if rule_hash_target.is_root() { SelectorMap::get_matching_rules( element, @@ -259,14 +255,10 @@ impl SelectorMap { cascade_level, shadow_cascade_order, ); - - // Sort only the rules we just added. - matching_rules_list[init_len..] - .sort_unstable_by_key(|block| (block.specificity, block.source_order())); } /// Adds rules in `rules` that match `element` to the `matching_rules` list. - fn get_matching_rules( + pub (crate) fn get_matching_rules( element: E, rules: &[Rule], matching_rules: &mut ApplicableDeclarationList, diff --git a/components/style/stylist.rs b/components/style/stylist.rs index c2601515002..33ce450151b 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -1257,7 +1257,7 @@ impl Stylist { let matches_document_rules = element.each_applicable_non_document_style_rule_data(|data, host| { - matching_context.with_shadow_host(host, |matching_context| { + matching_context.with_shadow_host(Some(host), |matching_context| { data.selectors_for_cache_revalidation.lookup( element, self.quirks_mode,