зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
838e209b31
Коммит
3685cf25a7
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче