Bug 1505489 - Add code to make part rules affect the style of the elements. r=heycam

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.

Depends on D32646

Differential Revision: https://phabricator.services.mozilla.com/D32647

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-06-11 17:42:41 +00:00
Родитель 838e209b31
Коммит 3685cf25a7
6 изменённых файлов: 100 добавлений и 27 удалений

Просмотреть файл

@ -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<F, E, R>(&mut self, host: E, f: F) -> R
pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, 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

Просмотреть файл

@ -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<F>(&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

Просмотреть файл

@ -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> {

Просмотреть файл

@ -54,6 +54,11 @@ 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.
///
@ -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<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 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();
}
}

Просмотреть файл

@ -182,10 +182,6 @@ impl SelectorMap<Rule> {
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<Rule> {
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<E, F>(
pub (crate) fn get_matching_rules<E, F>(
element: E,
rules: &[Rule],
matching_rules: &mut ApplicableDeclarationList,

Просмотреть файл

@ -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,