Auto merge of #16872 - jryans:matching-context, r=emilio

Create a MatchingContext to group related matching args

https://bugzilla.mozilla.org/show_bug.cgi?id=1364914

Upcoming changes for visited support and others as well need to pass more args through matching, so this creates a MatchingContext to group them together.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16872)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-05-16 09:45:36 -05:00 committed by GitHub
commit 7f6b28e241
9 changed files with 91 additions and 83 deletions

View file

@ -85,7 +85,7 @@ use net_traits::request::CorsSettings;
use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowQueryType;
use script_thread::Runnable;
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector_list};
use selectors::matching::{ElementSelectorFlags, MatchingContext, matches_selector_list};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_atoms::Atom;
@ -2414,7 +2414,7 @@ impl<'a> ::selectors::Element for Root<Element> {
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
_: &mut StyleRelations,
_: &mut MatchingContext,
_: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),

View file

@ -50,7 +50,7 @@ use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, Truste
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_atoms::Atom;
use servo_url::ServoUrl;
@ -654,7 +654,7 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
_: &mut StyleRelations,
_: &mut MatchingContext,
_: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@ -1152,7 +1152,7 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
fn match_non_ts_pseudo_class<F>(&self,
_: &NonTSPseudoClass,
_: &mut StyleRelations,
_: &mut MatchingContext,
_: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),

View file

@ -17,6 +17,7 @@ bitflags! {
/// the selector matching process.
///
/// This is used to implement efficient sharing.
#[derive(Default)]
pub flags StyleRelations: usize {
/// Whether this element is affected by an ID selector.
const AFFECTED_BY_ID_SELECTOR = 1 << 0,
@ -68,6 +69,16 @@ impl ElementSelectorFlags {
}
}
/// Data associated with the matching process for a element. This context is
/// used across many selectors for an element, so it's not appropriate for
/// transient data that applies to only a single selector.
#[derive(Default)]
pub struct MatchingContext {
/// Output that records certains relations between elements noticed during
/// matching (and also extended after matching).
pub relations: StyleRelations,
}
pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
element: &E,
parent_bf: Option<&BloomFilter>)
@ -79,7 +90,7 @@ pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
matches_selector(&selector.inner,
element,
parent_bf,
&mut StyleRelations::empty(),
&mut MatchingContext::default(),
&mut |_, _| {})
})
}
@ -108,7 +119,7 @@ fn may_match<E>(sel: &SelectorInner<E::Impl>,
pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
element: &E,
parent_bf: Option<&BloomFilter>,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
where E: Element,
@ -122,7 +133,7 @@ pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
}
// Match the selector.
matches_complex_selector(&selector.complex, element, relations, flags_setter)
matches_complex_selector(&selector.complex, element, context, flags_setter)
}
/// A result of selector matching, includes 3 failure types,
@ -178,7 +189,7 @@ enum SelectorMatchingResult {
/// Matches a complex selector.
pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
element: &E,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
where E: Element,
@ -186,7 +197,7 @@ pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
{
match matches_complex_selector_internal(selector.iter(),
element,
relations,
context,
flags_setter) {
SelectorMatchingResult::Matched => true,
_ => false
@ -195,14 +206,14 @@ pub fn matches_complex_selector<E, F>(selector: &ComplexSelector<E::Impl>,
fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
element: &E,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F)
-> SelectorMatchingResult
where E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
let matches_all_simple_selectors = selector_iter.all(|simple| {
matches_simple_selector(simple, element, relations, flags_setter)
matches_simple_selector(simple, element, context, flags_setter)
});
let combinator = selector_iter.next_sequence();
@ -233,7 +244,7 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
};
let result = matches_complex_selector_internal(selector_iter.clone(),
&element,
relations,
context,
flags_setter);
match (result, c) {
// Return the status immediately.
@ -276,7 +287,7 @@ fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Im
fn matches_simple_selector<E, F>(
selector: &Component<E::Impl>,
element: &E,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
where E: Element,
@ -285,7 +296,7 @@ fn matches_simple_selector<E, F>(
macro_rules! relation_if {
($ex:expr, $flag:ident) => {
if $ex {
*relations |= $flag;
context.relations |= $flag;
true
} else {
false
@ -341,7 +352,7 @@ fn matches_simple_selector<E, F>(
false
}
Component::NonTSPseudoClass(ref pc) => {
element.match_non_ts_pseudo_class(pc, relations, flags_setter)
element.match_non_ts_pseudo_class(pc, context, flags_setter)
}
Component::FirstChild => {
matches_first_child(element, flags_setter)
@ -385,7 +396,7 @@ fn matches_simple_selector<E, F>(
matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
}
Component::Negation(ref negated) => {
!negated.iter().all(|ss| matches_simple_selector(ss, element, relations, flags_setter))
!negated.iter().all(|ss| matches_simple_selector(ss, element, context, flags_setter))
}
}
}

View file

@ -5,7 +5,7 @@
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
//! style.
use matching::{ElementSelectorFlags, StyleRelations};
use matching::{ElementSelectorFlags, MatchingContext};
use parser::{AttrSelector, SelectorImpl};
use std::ascii::AsciiExt;
@ -141,7 +141,7 @@ pub trait Element: MatchAttr + Sized {
fn match_non_ts_pseudo_class<F>(&self,
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F) -> bool
where F: FnMut(&Self, ElementSelectorFlags);

View file

@ -64,7 +64,7 @@ use properties::style_structs::Font;
use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::ElementExt;
use selectors::Element;
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use shared_lock::Locked;
use sink::Push;
@ -1125,7 +1125,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@ -1219,7 +1219,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
},
NonTSPseudoClass::MozAny(ref sels) => {
sels.iter().any(|s| {
matches_complex_selector(s, self, relations, flags_setter)
matches_complex_selector(s, self, context, flags_setter)
})
}
NonTSPseudoClass::MozSystemMetric(ref s) |
@ -1376,7 +1376,7 @@ impl<'le> ElementExt for GeckoElement<'le> {
#[inline]
fn is_link(&self) -> bool {
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
&mut StyleRelations::empty(),
&mut MatchingContext::default(),
&mut |_, _| {})
}

View file

@ -24,7 +24,7 @@ use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_SMIL};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
use selectors::bloom::BloomFilter;
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::{ElementSelectorFlags, MatchingContext, StyleRelations};
use selectors::matching::AFFECTED_BY_PSEUDO_ELEMENTS;
use shared_lock::StylesheetGuards;
use sink::ForgetfulSink;
@ -895,8 +895,10 @@ pub trait MatchMethods : TElement {
sharing: StyleSharingBehavior)
{
// Perform selector matching for the primary style.
let mut primary_relations = StyleRelations::empty();
let _rule_node_changed = self.match_primary(context, data, &mut primary_relations);
let mut primary_matching_context = MatchingContext::default();
let _rule_node_changed = self.match_primary(context,
data,
&mut primary_matching_context);
// Cascade properties and compute primary values.
self.cascade_primary(context, data);
@ -910,7 +912,7 @@ pub trait MatchMethods : TElement {
// If we have any pseudo elements, indicate so in the primary StyleRelations.
if !data.styles().pseudos.is_empty() {
primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
primary_matching_context.relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
}
// If the style is shareable, add it to the LRU cache.
@ -930,7 +932,7 @@ pub trait MatchMethods : TElement {
.style_sharing_candidate_cache
.insert_if_possible(self,
data.styles().primary.values(),
primary_relations,
primary_matching_context.relations,
revalidation_match_results);
}
}
@ -950,7 +952,7 @@ pub trait MatchMethods : TElement {
fn match_primary(&self,
context: &mut StyleContext<Self>,
data: &mut ElementData,
relations: &mut StyleRelations)
matching_context: &mut MatchingContext)
-> bool
{
let implemented_pseudo = self.implemented_pseudo_element();
@ -1021,13 +1023,14 @@ pub trait MatchMethods : TElement {
};
// Compute the primary rule node.
*relations = stylist.push_applicable_declarations(&selector_matching_target,
stylist.push_applicable_declarations(&selector_matching_target,
Some(bloom),
style_attribute,
smil_override,
animation_rules,
pseudo_and_state,
&mut applicable_declarations,
matching_context,
&mut set_selector_flags);
let primary_rule_node =
@ -1082,6 +1085,7 @@ pub trait MatchMethods : TElement {
AnimationRules(None, None),
Some((&pseudo, ElementState::empty())),
&mut applicable_declarations,
&mut MatchingContext::default(),
&mut set_selector_flags);
if !applicable_declarations.is_empty() {

View file

@ -16,7 +16,7 @@ use gecko_bindings::structs::nsRestyleHint;
use heapsize::HeapSizeOf;
use selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap};
use selectors::{Element, MatchAttr};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::matching::matches_selector;
use selectors::parser::{AttrSelector, Combinator, Component, Selector};
use selectors::parser::{SelectorInner, SelectorMethods};
@ -348,7 +348,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
{
fn match_non_ts_pseudo_class<F>(&self,
pseudo_class: &NonTSPseudoClass,
relations: &mut StyleRelations,
context: &mut MatchingContext,
_setter: &mut F)
-> bool
where F: FnMut(&Self, ElementSelectorFlags),
@ -360,7 +360,7 @@ impl<'a, E> Element for ElementWrapper<'a, E>
use selectors::matching::matches_complex_selector;
if let NonTSPseudoClass::MozAny(ref selectors) = *pseudo_class {
return selectors.iter().any(|s| {
matches_complex_selector(s, self, relations, _setter)
matches_complex_selector(s, self, context, _setter)
})
}
}
@ -393,14 +393,14 @@ impl<'a, E> Element for ElementWrapper<'a, E>
let flag = pseudo_class.state_flag();
if flag.is_empty() {
return self.element.match_non_ts_pseudo_class(pseudo_class,
relations,
context,
&mut |_, _| {})
}
match self.snapshot().and_then(|s| s.state()) {
Some(snapshot_state) => snapshot_state.intersects(flag),
None => {
self.element.match_non_ts_pseudo_class(pseudo_class,
relations,
context,
&mut |_, _| {})
}
}
@ -780,7 +780,7 @@ impl DependencySet {
// either (or it doesn't matter because our parent posted a restyle
// for us above).
if !matches_selector(&dep.selector.inner, &selector_matching_target,
None, &mut StyleRelations::empty(),
None, &mut MatchingContext::default(),
&mut |_, _| {}) {
return true;
}
@ -857,11 +857,11 @@ impl DependencySet {
// change its matching behavior here.
let matched_then =
matches_selector(&dep.selector, &snapshot_el, None,
&mut StyleRelations::empty(),
&mut MatchingContext::default(),
&mut |_, _| {});
let matches_now =
matches_selector(&dep.selector, el, None,
&mut StyleRelations::empty(),
&mut MatchingContext::default(),
&mut |_, _| {});
if matched_then != matches_now {
hint.insert(dep.hint);

View file

@ -15,7 +15,7 @@ use fnv::FnvHashMap;
use restyle_hints::ElementSnapshot;
use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
use selectors::{Element, MatchAttrGeneric};
use selectors::matching::StyleRelations;
use selectors::matching::MatchingContext;
use selectors::parser::{AttrSelector, SelectorMethods};
use selectors::visitor::SelectorVisitor;
use std::borrow::Cow;
@ -580,7 +580,7 @@ impl MatchAttrGeneric for ServoElementSnapshot {
impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
fn is_link(&self) -> bool {
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
&mut StyleRelations::empty(),
&mut MatchingContext::default(),
&mut |_, _| {})
}

View file

@ -29,7 +29,7 @@ use selector_parser::{SelectorImpl, PseudoElement, SnapshotMap};
use selectors::Element;
use selectors::bloom::BloomFilter;
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_selector};
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext};
use selectors::parser::{AttrSelector, Combinator, Component, Selector, SelectorInner, SelectorIter};
use selectors::parser::{SelectorMethods, LocalName as LocalNameSelector};
use selectors::visitor::SelectorVisitor;
@ -707,7 +707,6 @@ impl Stylist {
}
};
let mut declarations = ApplicableDeclarationList::new();
self.push_applicable_declarations(element,
None,
@ -716,6 +715,7 @@ impl Stylist {
AnimationRules(None, None),
Some((pseudo, pseudo_state)),
&mut declarations,
&mut MatchingContext::default(),
&mut set_selector_flags);
if declarations.is_empty() {
return None
@ -834,8 +834,8 @@ impl Stylist {
///
/// This corresponds to `ElementRuleCollector` in WebKit.
///
/// The returned `StyleRelations` indicate hints about which kind of rules
/// have matched.
/// The `StyleRelations` recorded in `MatchingContext` indicate hints about
/// which kind of rules have matched.
pub fn push_applicable_declarations<E, V, F>(
&self,
element: &E,
@ -845,8 +845,8 @@ impl Stylist {
animation_rules: AnimationRules,
pseudo_element: Option<(&PseudoElement, ElementState)>,
applicable_declarations: &mut V,
context: &mut MatchingContext,
flags_setter: &mut F)
-> StyleRelations
where E: TElement,
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
F: FnMut(&E, ElementSelectorFlags),
@ -864,8 +864,6 @@ impl Stylist {
None => &self.element_map,
};
let mut relations = StyleRelations::empty();
debug!("Determining if style is shareable: pseudo: {}",
pseudo_element.is_some());
@ -874,10 +872,10 @@ impl Stylist {
pseudo_element,
parent_bf,
applicable_declarations,
&mut relations,
context,
flags_setter,
CascadeLevel::UANormal);
debug!("UA normal: {:?}", relations);
debug!("UA normal: {:?}", context.relations);
if pseudo_element.is_none() {
// Step 2: Presentational hints.
@ -890,9 +888,9 @@ impl Stylist {
}
}
// Never share style for elements with preshints
relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
context.relations |= AFFECTED_BY_PRESENTATIONAL_HINTS;
}
debug!("preshints: {:?}", relations);
debug!("preshints: {:?}", context.relations);
}
if element.matches_user_and_author_rules() {
@ -901,29 +899,29 @@ impl Stylist {
pseudo_element,
parent_bf,
applicable_declarations,
&mut relations,
context,
flags_setter,
CascadeLevel::UserNormal);
debug!("user normal: {:?}", relations);
debug!("user normal: {:?}", context.relations);
map.author.get_all_matching_rules(element,
pseudo_element,
parent_bf,
applicable_declarations,
&mut relations,
context,
flags_setter,
CascadeLevel::AuthorNormal);
debug!("author normal: {:?}", relations);
debug!("author normal: {:?}", context.relations);
// Step 4: Normal style attributes.
if let Some(sa) = style_attribute {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
context.relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push(
applicable_declarations,
ApplicableDeclarationBlock::from_declarations(sa.clone(),
CascadeLevel::StyleAttributeNormal));
}
debug!("style attr: {:?}", relations);
debug!("style attr: {:?}", context.relations);
// Step 5: SMIL override.
// Declarations from SVG SMIL animation elements.
@ -933,7 +931,7 @@ impl Stylist {
ApplicableDeclarationBlock::from_declarations(so.clone(),
CascadeLevel::SMILOverride));
}
debug!("SMIL: {:?}", relations);
debug!("SMIL: {:?}", context.relations);
// Step 6: Animations.
// The animations sheet (CSS animations, script-generated animations,
@ -944,7 +942,7 @@ impl Stylist {
ApplicableDeclarationBlock::from_declarations(anim,
CascadeLevel::Animations));
}
debug!("animation: {:?}", relations);
debug!("animation: {:?}", context.relations);
} else {
debug!("skipping non-agent rules");
}
@ -961,11 +959,9 @@ impl Stylist {
applicable_declarations,
ApplicableDeclarationBlock::from_declarations(anim, CascadeLevel::Transitions));
}
debug!("transition: {:?}", relations);
debug!("transition: {:?}", context.relations);
debug!("push_applicable_declarations: shareable: {:?}", relations);
relations
debug!("push_applicable_declarations: shareable: {:?}", context.relations);
}
/// Return whether the device is dirty, that is, whether the screen size or
@ -997,9 +993,6 @@ impl Stylist {
where E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{
use selectors::matching::StyleRelations;
use selectors::matching::matches_selector;
// Note that, by the time we're revalidating, we're guaranteed that the
// candidate and the entry have the same id, classes, and local name.
// This means we're guaranteed to get the same rulehash buckets for all
@ -1010,7 +1003,7 @@ impl Stylist {
results.push(matches_selector(selector,
element,
Some(bloom),
&mut StyleRelations::empty(),
&mut MatchingContext::default(),
flags_setter));
true
});
@ -1293,7 +1286,7 @@ impl SelectorMap<Rule> {
pseudo_element: Option<(&PseudoElement, ElementState)>,
parent_bf: Option<&BloomFilter>,
matching_rules_list: &mut V,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F,
cascade_level: CascadeLevel)
where E: Element<Impl=SelectorImpl>,
@ -1313,7 +1306,7 @@ impl SelectorMap<Rule> {
&self.id_hash,
&id,
matching_rules_list,
relations,
context,
flags_setter,
cascade_level)
}
@ -1325,7 +1318,7 @@ impl SelectorMap<Rule> {
&self.class_hash,
class,
matching_rules_list,
relations,
context,
flags_setter,
cascade_level);
});
@ -1336,7 +1329,7 @@ impl SelectorMap<Rule> {
&self.local_name_hash,
element.get_local_name(),
matching_rules_list,
relations,
context,
flags_setter,
cascade_level);
@ -1345,7 +1338,7 @@ impl SelectorMap<Rule> {
parent_bf,
&self.other,
matching_rules_list,
relations,
context,
flags_setter,
cascade_level);
@ -1384,7 +1377,7 @@ impl SelectorMap<Rule> {
hash: &FnvHashMap<Str, Vec<Rule>>,
key: &BorrowedStr,
matching_rules: &mut Vector,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F,
cascade_level: CascadeLevel)
where E: Element<Impl=SelectorImpl>,
@ -1399,7 +1392,7 @@ impl SelectorMap<Rule> {
parent_bf,
rules,
matching_rules,
relations,
context,
flags_setter,
cascade_level)
}
@ -1411,7 +1404,7 @@ impl SelectorMap<Rule> {
parent_bf: Option<&BloomFilter>,
rules: &[Rule],
matching_rules: &mut V,
relations: &mut StyleRelations,
context: &mut MatchingContext,
flags_setter: &mut F,
cascade_level: CascadeLevel)
where E: Element<Impl=SelectorImpl>,
@ -1443,7 +1436,7 @@ impl SelectorMap<Rule> {
if matches_selector(&rule.selector.inner,
element,
parent_bf,
relations,
context,
flags_setter) {
matching_rules.push(
rule.to_applicable_declaration_block(cascade_level));