style: Stop special-casing a few attributes for style sharing, and use a visitor to track dependencies.

Also, simplify all the pre-snapshot attribute hacks in the script and style
code.

MozReview-Commit-ID: 6c9ipeb7Tnr
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit is contained in:
Emilio Cobos Álvarez 2017-04-07 03:17:29 +02:00
parent 1748150497
commit 0ea58d1ffa
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
9 changed files with 161 additions and 312 deletions

View file

@ -100,7 +100,6 @@ use std::sync::Arc;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::context::{QuirksMode, ReflowGoal};
use style::element_state::*;
use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
use style::restyle_hints::RESTYLE_SELF;
@ -2236,14 +2235,6 @@ impl VirtualMethods for Element {
}
}
},
_ if attr.namespace() == &ns!() => {
if fragment_affecting_attributes().iter().any(|a| a == attr.local_name()) ||
common_style_affecting_attributes().iter().any(|a| &a.attr_name == attr.local_name()) ||
rare_style_affecting_attributes().iter().any(|a| a == attr.local_name())
{
node.dirty(NodeDamage::OtherNodeDamage);
}
},
_ => {},
};

View file

@ -145,15 +145,16 @@ impl<Impl: SelectorImpl> SelectorMethods for Selector<Impl> {
}
}
impl<Impl: SelectorImpl> SelectorMethods for ComplexSelector<Impl> {
impl<Impl: SelectorImpl> SelectorMethods for Arc<ComplexSelector<Impl>> {
type Impl = Impl;
fn visit<V>(&self, visitor: &mut V) -> bool
where V: SelectorVisitor<Impl = Impl>,
{
let mut current = self;
let mut combinator = None;
loop {
if !visitor.visit_complex_selector(current) {
if !visitor.visit_complex_selector(current, combinator) {
return false;
}
@ -164,7 +165,10 @@ impl<Impl: SelectorImpl> SelectorMethods for ComplexSelector<Impl> {
}
match current.next {
Some((ref next, _)) => current = next,
Some((ref next, next_combinator)) => {
current = next;
combinator = Some(next_combinator);
}
None => break,
}
}
@ -222,30 +226,6 @@ pub struct ComplexSelector<Impl: SelectorImpl> {
pub next: Option<(Arc<ComplexSelector<Impl>>, Combinator)>, // c.next is left of c
}
impl<Impl: SelectorImpl> ComplexSelector<Impl> {
/// Visits this selectors and all the ones to the left of it, until a
/// visitor method returns `false`.
pub fn visit<V>(&self, visitor: &mut V) -> bool
where V: SelectorVisitor<Impl = Impl>,
{
let mut current = self;
loop {
for selector in &current.compound_selector {
if !selector.visit(visitor) {
return false;
}
}
match current.next {
Some((ref next, _)) => current = next,
None => break,
}
}
true
}
}
#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)]
pub enum Combinator {
Child, // >

View file

@ -6,7 +6,8 @@
#![deny(missing_docs)]
use parser::{AttrSelector, ComplexSelector, SelectorImpl, SimpleSelector};
use parser::{AttrSelector, Combinator, ComplexSelector, SelectorImpl, SimpleSelector};
use std::sync::Arc;
/// A trait to visit selector properties.
///
@ -24,7 +25,13 @@ pub trait SelectorVisitor {
}
/// Visits a complex selector.
fn visit_complex_selector(&mut self, _: &ComplexSelector<Self::Impl>) -> bool {
///
/// Gets the combinator to the right of the selector, or `None` if the
/// selector is the leftmost one.
fn visit_complex_selector(&mut self,
_: &Arc<ComplexSelector<Self::Impl>>,
_combinator_to_right: Option<Combinator>)
-> bool {
true
}

View file

@ -10,11 +10,12 @@ use gecko_bindings::structs::CSSPseudoClassType;
use gecko_bindings::structs::nsIAtom;
use restyle_hints::complex_selector_to_state;
use selector_parser::{SelectorParser, PseudoElementCascadeType};
use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
use selectors::parser::{AttrSelector, ComplexSelector, SelectorMethods};
use selectors::parser::{ComplexSelector, SelectorMethods};
use selectors::visitor::SelectorVisitor;
use std::borrow::Cow;
use std::fmt;
use std::ptr;
use std::sync::Arc;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
/// A representation of a CSS pseudo-element.
@ -218,7 +219,7 @@ macro_rules! pseudo_class_name {
///
/// TODO(emilio): We disallow combinators and pseudos here, so we
/// should use SimpleSelector instead
MozAny(Vec<ComplexSelector<SelectorImpl>>),
MozAny(Vec<Arc<ComplexSelector<SelectorImpl>>>),
}
}
}
@ -261,24 +262,20 @@ impl ToCss for NonTSPseudoClass {
}
impl SelectorMethods for NonTSPseudoClass {
#[inline]
fn affects_siblings(&self) -> bool {
match *self {
NonTSPseudoClass::MozAny(ref selectors) => {
selectors.iter().any(|s| s.affects_siblings())
type Impl = SelectorImpl;
fn visit<V>(&self, visitor: &mut V) -> bool
where V: SelectorVisitor<Impl = Self::Impl>,
{
if let NonTSPseudoClass::MozAny(ref selectors) = *self {
for selector in selectors {
if !selector.visit(visitor) {
return false;
}
_ => false
}
}
#[inline]
fn matches_non_common_style_affecting_attribute(&self) -> bool {
match *self {
NonTSPseudoClass::MozAny(ref selectors) => {
selectors.iter().any(|s| s.matches_non_common_style_affecting_attribute())
}
_ => false
}
true
}
}
@ -364,15 +361,6 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type PseudoElement = PseudoElement;
type NonTSPseudoClass = NonTSPseudoClass;
fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
attr_exists_selector_is_shareable(attr_selector)
}
fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
value: &Self::AttrValue) -> bool {
attr_equals_selector_is_shareable(attr_selector, value)
}
}
impl<'a> ::selectors::Parser for SelectorParser<'a> {
@ -413,7 +401,7 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
}, )*
"-moz-any" => {
let selectors = parser.parse_comma_separated(|input| {
ComplexSelector::parse(self, input)
ComplexSelector::parse(self, input).map(Arc::new)
})?;
// Selectors inside `:-moz-any` may not include combinators.
if selectors.iter().any(|s| s.next.is_some()) {

View file

@ -7,7 +7,7 @@
#![allow(unsafe_code)]
#![deny(missing_docs)]
use {Atom, LocalName};
use Atom;
use animation::{self, Animation, PropertyAnimation};
use atomic_refcell::AtomicRefMut;
use cache::{LRUCache, LRUCacheMutIterator};
@ -38,26 +38,6 @@ fn relations_are_shareable(relations: &StyleRelations) -> bool {
AFFECTED_BY_PRESENTATIONAL_HINTS)
}
fn create_common_style_affecting_attributes_from_element<E: TElement>(element: &E)
-> CommonStyleAffectingAttributes {
let mut flags = CommonStyleAffectingAttributes::empty();
for attribute_info in &common_style_affecting_attributes() {
match attribute_info.mode {
CommonStyleAffectingAttributeMode::IsPresent(flag) => {
if element.has_attr(&ns!(), &attribute_info.attr_name) {
flags.insert(flag)
}
}
CommonStyleAffectingAttributeMode::IsEqual(ref target_value, flag) => {
if element.attr_equals(&ns!(), &attribute_info.attr_name, target_value) {
flags.insert(flag)
}
}
}
}
flags
}
/// Information regarding a style sharing candidate.
///
/// Note that this information is stored in TLS and cleared after the traversal,
@ -70,16 +50,13 @@ struct StyleSharingCandidate<E: TElement> {
/// The element. We use SendElement here so that the cache may live in
/// ScopedTLS.
element: SendElement<E>,
/// The cached common style affecting attribute info.
common_style_affecting_attributes: Option<CommonStyleAffectingAttributes>,
/// The cached class names.
class_attributes: Option<Vec<Atom>>,
}
impl<E: TElement> PartialEq<StyleSharingCandidate<E>> for StyleSharingCandidate<E> {
fn eq(&self, other: &Self) -> bool {
self.element == other.element &&
self.common_style_affecting_attributes == other.common_style_affecting_attributes
self.element == other.element
}
}
@ -115,17 +92,14 @@ pub enum CacheMiss {
StyleAttr,
/// The element and the candidate class names didn't match.
Class,
/// The element and the candidate common style affecting attributes didn't
/// match.
CommonStyleAffectingAttributes,
/// The presentation hints didn't match.
PresHints,
/// The element and the candidate didn't match the same set of
/// sibling-affecting rules.
SiblingRules,
/// The element and the candidate didn't match the same set of non-common
/// style affecting attribute selectors.
NonCommonAttrRules,
/// The element and the candidate didn't match the same set of style
/// affecting attribute selectors.
AttrRules,
}
fn element_matches_candidate<E: TElement>(element: &E,
@ -175,12 +149,6 @@ fn element_matches_candidate<E: TElement>(element: &E,
miss!(Class)
}
if !have_same_common_style_affecting_attributes(element,
candidate,
candidate_element) {
miss!(CommonStyleAffectingAttributes)
}
if !have_same_presentational_hints(element, candidate_element) {
miss!(PresHints)
}
@ -191,10 +159,10 @@ fn element_matches_candidate<E: TElement>(element: &E,
miss!(SiblingRules)
}
if !match_same_not_common_style_affecting_attributes_rules(element,
if !match_same_style_affecting_attributes_rules(element,
candidate_element,
shared_context) {
miss!(NonCommonAttrRules)
miss!(AttrRules)
}
let data = candidate_element.borrow_data().unwrap();
@ -204,20 +172,10 @@ fn element_matches_candidate<E: TElement>(element: &E,
Ok(current_styles.primary.clone())
}
fn have_same_common_style_affecting_attributes<E: TElement>(element: &E,
candidate: &mut StyleSharingCandidate<E>,
candidate_element: &E) -> bool {
if candidate.common_style_affecting_attributes.is_none() {
candidate.common_style_affecting_attributes =
Some(create_common_style_affecting_attributes_from_element(candidate_element))
}
create_common_style_affecting_attributes_from_element(element) ==
candidate.common_style_affecting_attributes.unwrap()
}
fn have_same_presentational_hints<E: TElement>(element: &E, candidate: &E) -> bool {
let mut first = ForgetfulSink::new();
element.synthesize_presentational_hints_for_legacy_attributes(&mut first);
if cfg!(debug_assertions) {
let mut second = vec![];
candidate.synthesize_presentational_hints_for_legacy_attributes(&mut second);
@ -228,82 +186,6 @@ fn have_same_presentational_hints<E: TElement>(element: &E, candidate: &E) -> bo
first.is_empty()
}
bitflags! {
/// A set of common style-affecting attributes we check separately to
/// optimize the style sharing cache.
pub flags CommonStyleAffectingAttributes: u8 {
/// The `hidden` attribute.
const HIDDEN_ATTRIBUTE = 0x01,
/// The `nowrap` attribute.
const NO_WRAP_ATTRIBUTE = 0x02,
/// The `align="left"` attribute.
const ALIGN_LEFT_ATTRIBUTE = 0x04,
/// The `align="center"` attribute.
const ALIGN_CENTER_ATTRIBUTE = 0x08,
/// The `align="right"` attribute.
const ALIGN_RIGHT_ATTRIBUTE = 0x10,
}
}
/// The information of how to match a given common-style affecting attribute.
pub struct CommonStyleAffectingAttributeInfo {
/// The attribute name.
pub attr_name: LocalName,
/// The matching mode for the attribute.
pub mode: CommonStyleAffectingAttributeMode,
}
/// How should we match a given common style-affecting attribute?
#[derive(Clone)]
pub enum CommonStyleAffectingAttributeMode {
/// Just for presence?
IsPresent(CommonStyleAffectingAttributes),
/// For presence and equality with a given value.
IsEqual(Atom, CommonStyleAffectingAttributes),
}
/// The common style affecting attribute array.
///
/// TODO: This should be a `const static` or similar, but couldn't be because
/// `Atom`s have destructors.
#[inline]
pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo; 5] {
[
CommonStyleAffectingAttributeInfo {
attr_name: local_name!("hidden"),
mode: CommonStyleAffectingAttributeMode::IsPresent(HIDDEN_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
attr_name: local_name!("nowrap"),
mode: CommonStyleAffectingAttributeMode::IsPresent(NO_WRAP_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
attr_name: local_name!("align"),
mode: CommonStyleAffectingAttributeMode::IsEqual(atom!("left"), ALIGN_LEFT_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
attr_name: local_name!("align"),
mode: CommonStyleAffectingAttributeMode::IsEqual(atom!("center"), ALIGN_CENTER_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
attr_name: local_name!("align"),
mode: CommonStyleAffectingAttributeMode::IsEqual(atom!("right"), ALIGN_RIGHT_ATTRIBUTE),
}
]
}
/// Attributes that, if present, disable style sharing. All legacy HTML
/// attributes must be in either this list or
/// `common_style_affecting_attributes`. See the comment in
/// `synthesize_presentational_hints_for_legacy_attributes`.
///
/// TODO(emilio): This is not accurate now, we don't disable style sharing for
/// this now since we check for attribute selectors in the stylesheet. Consider
/// removing this.
pub fn rare_style_affecting_attributes() -> [LocalName; 4] {
[local_name!("bgcolor"), local_name!("border"), local_name!("colspan"), local_name!("rowspan")]
}
fn have_same_class<E: TElement>(element: &E,
candidate: &mut StyleSharingCandidate<E>,
candidate_element: &E) -> bool {
@ -322,10 +204,10 @@ fn have_same_class<E: TElement>(element: &E,
// TODO: These re-match the candidate every time, which is suboptimal.
#[inline]
fn match_same_not_common_style_affecting_attributes_rules<E: TElement>(element: &E,
fn match_same_style_affecting_attributes_rules<E: TElement>(element: &E,
candidate: &E,
ctx: &SharedStyleContext) -> bool {
ctx.stylist.match_same_not_common_style_affecting_attributes_rules(element, candidate)
ctx.stylist.match_same_style_affecting_attributes_rules(element, candidate)
}
#[inline]
@ -387,7 +269,6 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
self.cache.insert(StyleSharingCandidate {
element: unsafe { SendElement::new(*element) },
common_style_affecting_attributes: None,
class_attributes: None,
});
}
@ -1136,10 +1017,9 @@ pub trait MatchMethods : TElement {
},
// Too expensive failure, give up, we don't want another
// one of these.
CacheMiss::CommonStyleAffectingAttributes |
CacheMiss::PresHints |
CacheMiss::SiblingRules |
CacheMiss::NonCommonAttrRules => break,
CacheMiss::AttrRules => break,
_ => {}
}
}

View file

@ -18,6 +18,7 @@ use selectors::{Element, MatchAttr};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::matches_complex_selector;
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector};
use selectors::visitor::SelectorVisitor;
use std::clone::Clone;
use std::sync::Arc;
@ -399,6 +400,22 @@ fn is_attr_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
}
}
fn is_sibling_affecting_selector(sel: &SimpleSelector<SelectorImpl>) -> bool {
match *sel {
SimpleSelector::FirstChild |
SimpleSelector::LastChild |
SimpleSelector::OnlyChild |
SimpleSelector::NthChild(..) |
SimpleSelector::NthLastChild(..) |
SimpleSelector::NthOfType(..) |
SimpleSelector::NthLastOfType(..) |
SimpleSelector::FirstOfType |
SimpleSelector::LastOfType |
SimpleSelector::OnlyOfType => true,
_ => false,
}
}
fn combinator_to_restyle_hint(combinator: Option<Combinator>) -> RestyleHint {
match combinator {
None => RESTYLE_SELF,
@ -458,6 +475,74 @@ struct Dependency {
sensitivities: Sensitivities,
}
/// A visitor struct that collects information for a given selector.
///
/// This is the struct responsible of adding dependencies for a given complex
/// selector.
pub struct SelectorDependencyVisitor<'a> {
dependency_set: &'a mut DependencySet,
affects_siblings: bool,
affected_by_attribute: bool,
}
impl<'a> SelectorDependencyVisitor<'a> {
/// Create a new `SelectorDependencyVisitor`.
pub fn new(dependency_set: &'a mut DependencySet) -> Self {
SelectorDependencyVisitor {
dependency_set: dependency_set,
affects_siblings: false,
affected_by_attribute: false,
}
}
/// Returns whether this visitor has known of a sibling-dependent selector.
pub fn affects_siblings(&self) -> bool {
self.affects_siblings
}
/// Returns whether this visitor has known of a attribute-dependent
/// selector.
pub fn affected_by_attribute(&self) -> bool {
self.affected_by_attribute
}
}
impl<'a> SelectorVisitor for SelectorDependencyVisitor<'a> {
type Impl = SelectorImpl;
fn visit_complex_selector(&mut self,
selector: &Arc<ComplexSelector<SelectorImpl>>,
combinator: Option<Combinator>)
-> bool
{
let mut sensitivities = Sensitivities::new();
for s in &selector.compound_selector {
sensitivities.states.insert(selector_to_state(s));
if !self.affects_siblings {
self.affects_siblings = is_sibling_affecting_selector(s);
}
if !sensitivities.attrs {
sensitivities.attrs = is_attr_selector(s);
}
}
let hint = combinator_to_restyle_hint(combinator);
self.affected_by_attribute |= sensitivities.attrs;
self.affects_siblings |= hint.intersects(RESTYLE_LATER_SIBLINGS);
if !sensitivities.is_empty() {
self.dependency_set.add_dependency(Dependency {
selector: selector.clone(),
hint: hint,
sensitivities: sensitivities,
});
}
true
}
}
/// A set of dependencies for a given stylist.
///
/// Note that there are measurable perf wins from storing them separately
@ -476,12 +561,12 @@ pub struct DependencySet {
impl DependencySet {
fn add_dependency(&mut self, dep: Dependency) {
let affects_attrs = dep.sensitivities.attrs;
let affected_by_attribute = dep.sensitivities.attrs;
let affects_states = !dep.sensitivities.states.is_empty();
if affects_attrs && affects_states {
if affected_by_attribute && affects_states {
self.common_deps.push(dep)
} else if affects_attrs {
} else if affected_by_attribute {
self.attr_deps.push(dep)
} else {
self.state_deps.push(dep)
@ -502,46 +587,6 @@ impl DependencySet {
self.common_deps.len() + self.attr_deps.len() + self.state_deps.len()
}
/// Create the needed dependencies that a given selector creates, and add
/// them to the set.
pub fn note_selector(&mut self, selector: &Arc<ComplexSelector<SelectorImpl>>) {
let mut cur = selector;
let mut combinator: Option<Combinator> = None;
loop {
let mut sensitivities = Sensitivities::new();
for s in &cur.compound_selector {
sensitivities.states.insert(selector_to_state(s));
if !sensitivities.attrs {
sensitivities.attrs = is_attr_selector(s);
}
// NOTE(emilio): I haven't thought this thoroughly, but we may
// not need to do anything for combinators inside negations.
//
// Or maybe we do, and need to call note_selector recursively
// here to account for them correctly, but keep the
// sensitivities of the parent?
//
// In any case, perhaps we should just drop it, see bug 1348802.
}
if !sensitivities.is_empty() {
self.add_dependency(Dependency {
selector: cur.clone(),
hint: combinator_to_restyle_hint(combinator),
sensitivities: sensitivities,
});
}
cur = match cur.next {
Some((ref sel, comb)) => {
combinator = Some(comb);
sel
}
None => break,
}
}
}
/// Clear this dependency set.
pub fn clear(&mut self) {
self.common_deps.clear();

View file

@ -7,9 +7,8 @@
#![deny(missing_docs)]
use cssparser::Parser as CssParser;
use matching::{common_style_affecting_attributes, CommonStyleAffectingAttributeMode};
use selectors::Element;
use selectors::parser::{AttrSelector, SelectorList};
use selectors::parser::SelectorList;
use std::fmt::Debug;
use stylesheets::{Origin, Namespaces};
@ -130,41 +129,3 @@ impl SelectorImpl {
})
}
}
/// Checks whether we can share style if an element matches a given
/// attribute-selector that checks for existence (`[attr_name]`) easily.
///
/// We could do the same thing that we do for sibling rules and keep optimizing
/// these common attributes, but we'd have to measure how common it is.
pub fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<SelectorImpl>) -> bool {
// NB(pcwalton): If you update this, remember to update the corresponding list in
// `can_share_style_with()` as well.
common_style_affecting_attributes().iter().any(|common_attr_info| {
common_attr_info.attr_name == attr_selector.name && match common_attr_info.mode {
CommonStyleAffectingAttributeMode::IsPresent(_) => true,
CommonStyleAffectingAttributeMode::IsEqual(..) => false,
}
})
}
/// Checks whether we can share style if an element matches a given
/// attribute-selector that checks for equality (`[attr_name="attr_value"]`)
/// easily.
///
/// We could do the same thing that we do for sibling rules and keep optimizing
/// these common attributes, but we'd have to measure how common it is.
pub fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<SelectorImpl>,
value: &AttrValue) -> bool {
// FIXME(pcwalton): Remove once we start actually supporting RTL text. This is in
// here because the UA style otherwise disables all style sharing completely.
// FIXME(SimonSapin): should this be the attribute *name* rather than value?
atom!("dir") == *value ||
common_style_affecting_attributes().iter().any(|common_attr_info| {
common_attr_info.attr_name == attr_selector.name && match common_attr_info.mode {
CommonStyleAffectingAttributeMode::IsEqual(ref target_value, _) => {
*target_value == *value
}
CommonStyleAffectingAttributeMode::IsPresent(_) => false,
}
})
}

View file

@ -12,10 +12,10 @@ use cssparser::{Parser as CssParser, ToCss, serialize_identifier};
use element_state::ElementState;
use restyle_hints::ElementSnapshot;
use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
use selectors::{Element, MatchAttrGeneric};
use selectors::matching::StyleRelations;
use selectors::parser::{AttrSelector, SelectorMethods};
use selectors::visitor::SelectorVisitor;
use std::borrow::Cow;
use std::fmt;
use std::fmt::Debug;
@ -199,10 +199,14 @@ impl ToCss for NonTSPseudoClass {
}
impl SelectorMethods for NonTSPseudoClass {
#[inline]
fn affects_siblings(&self) -> bool { false }
#[inline]
fn matches_non_common_style_affecting_attribute(&self) -> bool { false }
type Impl = SelectorImpl;
fn visit<V>(&self, _: &mut V) -> bool
where V: SelectorVisitor<Impl = Self::Impl>
{
true
}
}
impl NonTSPseudoClass {
@ -251,15 +255,6 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type NamespaceUrl = Namespace;
type BorrowedLocalName = LocalName;
type BorrowedNamespaceUrl = Namespace;
fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
attr_exists_selector_is_shareable(attr_selector)
}
fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
value: &Self::AttrValue) -> bool {
attr_equals_selector_is_shareable(attr_selector, value)
}
}
impl<'a> ::selectors::Parser for SelectorParser<'a> {

View file

@ -17,7 +17,7 @@ use properties::{self, CascadeFlags, ComputedValues};
#[cfg(feature = "servo")]
use properties::INHERIT_ALL;
use properties::PropertyDeclarationBlock;
use restyle_hints::{RestyleHint, DependencySet};
use restyle_hints::{RestyleHint, DependencySet, SelectorDependencyVisitor};
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use selector_parser::{SelectorImpl, PseudoElement, Snapshot};
use selectors::Element;
@ -117,7 +117,7 @@ pub struct Stylist {
/// Selectors in the page matching elements with non-common style-affecting
/// attributes.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
non_common_style_affecting_attributes_selectors: Vec<Selector<SelectorImpl>>,
style_affecting_attributes_selectors: Vec<Selector<SelectorImpl>>,
}
/// This struct holds data which user of Stylist may want to extract
@ -169,9 +169,8 @@ impl Stylist {
rule_tree: RuleTree::new(),
state_deps: DependencySet::new(),
// XXX remember resetting them!
sibling_affecting_selectors: vec![],
non_common_style_affecting_attributes_selectors: vec![]
style_affecting_attributes_selectors: vec![]
};
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
@ -226,7 +225,7 @@ impl Stylist {
self.animations.clear();
self.sibling_affecting_selectors.clear();
self.non_common_style_affecting_attributes_selectors.clear();
self.style_affecting_attributes_selectors.clear();
extra_data.clear_font_faces();
@ -249,7 +248,7 @@ impl Stylist {
debug!(" - Got {} sibling-affecting selectors",
self.sibling_affecting_selectors.len());
debug!(" - Got {} non-common-style-attribute-affecting selectors",
self.non_common_style_affecting_attributes_selectors.len());
self.style_affecting_attributes_selectors.len());
debug!(" - Got {} deps for style-hint calculation",
self.state_deps.len());
@ -300,13 +299,16 @@ impl Stylist {
self.rules_source_order += 1;
for selector in &style_rule.selectors.0 {
self.state_deps.note_selector(&selector.complex_selector);
if selector.affects_siblings() {
let mut visitor =
SelectorDependencyVisitor::new(&mut self.state_deps);
selector.visit(&mut visitor);
if visitor.affects_siblings() {
self.sibling_affecting_selectors.push(selector.clone());
}
if selector.matches_non_common_style_affecting_attribute() {
self.non_common_style_affecting_attributes_selectors.push(selector.clone());
if visitor.affected_by_attribute() {
self.style_affecting_attributes_selectors.push(selector.clone());
}
}
}
@ -765,7 +767,7 @@ impl Stylist {
///
/// This is used to test elements and candidates in the style-sharing
/// candidate cache.
pub fn match_same_not_common_style_affecting_attributes_rules<E>(&self,
pub fn match_same_style_affecting_attributes_rules<E>(&self,
element: &E,
candidate: &E) -> bool
where E: TElement,
@ -779,7 +781,7 @@ impl Stylist {
//
// TODO(emilio): Use the bloom filter, since they contain the element's
// ancestor chain and it's correct for the candidate too.
for ref selector in self.non_common_style_affecting_attributes_selectors.iter() {
for ref selector in self.style_affecting_attributes_selectors.iter() {
let element_matches =
matches_complex_selector(&selector.complex_selector, element,
None, &mut StyleRelations::empty(),