mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
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:
parent
1748150497
commit
0ea58d1ffa
9 changed files with 161 additions and 312 deletions
|
@ -100,7 +100,6 @@ use std::sync::Arc;
|
||||||
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
||||||
use style::context::{QuirksMode, ReflowGoal};
|
use style::context::{QuirksMode, ReflowGoal};
|
||||||
use style::element_state::*;
|
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::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
|
||||||
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
|
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
|
||||||
use style::restyle_hints::RESTYLE_SELF;
|
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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
type Impl = Impl;
|
||||||
|
|
||||||
fn visit<V>(&self, visitor: &mut V) -> bool
|
fn visit<V>(&self, visitor: &mut V) -> bool
|
||||||
where V: SelectorVisitor<Impl = Impl>,
|
where V: SelectorVisitor<Impl = Impl>,
|
||||||
{
|
{
|
||||||
let mut current = self;
|
let mut current = self;
|
||||||
|
let mut combinator = None;
|
||||||
loop {
|
loop {
|
||||||
if !visitor.visit_complex_selector(current) {
|
if !visitor.visit_complex_selector(current, combinator) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +165,10 @@ impl<Impl: SelectorImpl> SelectorMethods for ComplexSelector<Impl> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match current.next {
|
match current.next {
|
||||||
Some((ref next, _)) => current = next,
|
Some((ref next, next_combinator)) => {
|
||||||
|
current = next;
|
||||||
|
combinator = Some(next_combinator);
|
||||||
|
}
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,30 +226,6 @@ pub struct ComplexSelector<Impl: SelectorImpl> {
|
||||||
pub next: Option<(Arc<ComplexSelector<Impl>>, Combinator)>, // c.next is left of c
|
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 ¤t.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)]
|
#[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)]
|
||||||
pub enum Combinator {
|
pub enum Combinator {
|
||||||
Child, // >
|
Child, // >
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![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.
|
/// A trait to visit selector properties.
|
||||||
///
|
///
|
||||||
|
@ -24,7 +25,13 @@ pub trait SelectorVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visits a complex selector.
|
/// 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
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@ use gecko_bindings::structs::CSSPseudoClassType;
|
||||||
use gecko_bindings::structs::nsIAtom;
|
use gecko_bindings::structs::nsIAtom;
|
||||||
use restyle_hints::complex_selector_to_state;
|
use restyle_hints::complex_selector_to_state;
|
||||||
use selector_parser::{SelectorParser, PseudoElementCascadeType};
|
use selector_parser::{SelectorParser, PseudoElementCascadeType};
|
||||||
use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
|
use selectors::parser::{ComplexSelector, SelectorMethods};
|
||||||
use selectors::parser::{AttrSelector, ComplexSelector, SelectorMethods};
|
use selectors::visitor::SelectorVisitor;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::sync::Arc;
|
||||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
|
|
||||||
/// A representation of a CSS pseudo-element.
|
/// 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
|
/// TODO(emilio): We disallow combinators and pseudos here, so we
|
||||||
/// should use SimpleSelector instead
|
/// 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 {
|
impl SelectorMethods for NonTSPseudoClass {
|
||||||
#[inline]
|
type Impl = SelectorImpl;
|
||||||
fn affects_siblings(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
NonTSPseudoClass::MozAny(ref selectors) => {
|
|
||||||
selectors.iter().any(|s| s.affects_siblings())
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
fn visit<V>(&self, visitor: &mut V) -> bool
|
||||||
fn matches_non_common_style_affecting_attribute(&self) -> bool {
|
where V: SelectorVisitor<Impl = Self::Impl>,
|
||||||
match *self {
|
{
|
||||||
NonTSPseudoClass::MozAny(ref selectors) => {
|
if let NonTSPseudoClass::MozAny(ref selectors) = *self {
|
||||||
selectors.iter().any(|s| s.matches_non_common_style_affecting_attribute())
|
for selector in selectors {
|
||||||
|
if !selector.visit(visitor) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,15 +361,6 @@ impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
|
|
||||||
type PseudoElement = PseudoElement;
|
type PseudoElement = PseudoElement;
|
||||||
type NonTSPseudoClass = NonTSPseudoClass;
|
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> {
|
impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
||||||
|
@ -413,7 +401,7 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
||||||
}, )*
|
}, )*
|
||||||
"-moz-any" => {
|
"-moz-any" => {
|
||||||
let selectors = parser.parse_comma_separated(|input| {
|
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.
|
// Selectors inside `:-moz-any` may not include combinators.
|
||||||
if selectors.iter().any(|s| s.next.is_some()) {
|
if selectors.iter().any(|s| s.next.is_some()) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use {Atom, LocalName};
|
use Atom;
|
||||||
use animation::{self, Animation, PropertyAnimation};
|
use animation::{self, Animation, PropertyAnimation};
|
||||||
use atomic_refcell::AtomicRefMut;
|
use atomic_refcell::AtomicRefMut;
|
||||||
use cache::{LRUCache, LRUCacheMutIterator};
|
use cache::{LRUCache, LRUCacheMutIterator};
|
||||||
|
@ -38,26 +38,6 @@ fn relations_are_shareable(relations: &StyleRelations) -> bool {
|
||||||
AFFECTED_BY_PRESENTATIONAL_HINTS)
|
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.
|
/// Information regarding a style sharing candidate.
|
||||||
///
|
///
|
||||||
/// Note that this information is stored in TLS and cleared after the traversal,
|
/// 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
|
/// The element. We use SendElement here so that the cache may live in
|
||||||
/// ScopedTLS.
|
/// ScopedTLS.
|
||||||
element: SendElement<E>,
|
element: SendElement<E>,
|
||||||
/// The cached common style affecting attribute info.
|
|
||||||
common_style_affecting_attributes: Option<CommonStyleAffectingAttributes>,
|
|
||||||
/// The cached class names.
|
/// The cached class names.
|
||||||
class_attributes: Option<Vec<Atom>>,
|
class_attributes: Option<Vec<Atom>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: TElement> PartialEq<StyleSharingCandidate<E>> for StyleSharingCandidate<E> {
|
impl<E: TElement> PartialEq<StyleSharingCandidate<E>> for StyleSharingCandidate<E> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.element == other.element &&
|
self.element == other.element
|
||||||
self.common_style_affecting_attributes == other.common_style_affecting_attributes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,17 +92,14 @@ pub enum CacheMiss {
|
||||||
StyleAttr,
|
StyleAttr,
|
||||||
/// The element and the candidate class names didn't match.
|
/// The element and the candidate class names didn't match.
|
||||||
Class,
|
Class,
|
||||||
/// The element and the candidate common style affecting attributes didn't
|
|
||||||
/// match.
|
|
||||||
CommonStyleAffectingAttributes,
|
|
||||||
/// The presentation hints didn't match.
|
/// The presentation hints didn't match.
|
||||||
PresHints,
|
PresHints,
|
||||||
/// The element and the candidate didn't match the same set of
|
/// The element and the candidate didn't match the same set of
|
||||||
/// sibling-affecting rules.
|
/// sibling-affecting rules.
|
||||||
SiblingRules,
|
SiblingRules,
|
||||||
/// The element and the candidate didn't match the same set of non-common
|
/// The element and the candidate didn't match the same set of style
|
||||||
/// style affecting attribute selectors.
|
/// affecting attribute selectors.
|
||||||
NonCommonAttrRules,
|
AttrRules,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn element_matches_candidate<E: TElement>(element: &E,
|
fn element_matches_candidate<E: TElement>(element: &E,
|
||||||
|
@ -175,12 +149,6 @@ fn element_matches_candidate<E: TElement>(element: &E,
|
||||||
miss!(Class)
|
miss!(Class)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !have_same_common_style_affecting_attributes(element,
|
|
||||||
candidate,
|
|
||||||
candidate_element) {
|
|
||||||
miss!(CommonStyleAffectingAttributes)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !have_same_presentational_hints(element, candidate_element) {
|
if !have_same_presentational_hints(element, candidate_element) {
|
||||||
miss!(PresHints)
|
miss!(PresHints)
|
||||||
}
|
}
|
||||||
|
@ -191,10 +159,10 @@ fn element_matches_candidate<E: TElement>(element: &E,
|
||||||
miss!(SiblingRules)
|
miss!(SiblingRules)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !match_same_not_common_style_affecting_attributes_rules(element,
|
if !match_same_style_affecting_attributes_rules(element,
|
||||||
candidate_element,
|
candidate_element,
|
||||||
shared_context) {
|
shared_context) {
|
||||||
miss!(NonCommonAttrRules)
|
miss!(AttrRules)
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = candidate_element.borrow_data().unwrap();
|
let data = candidate_element.borrow_data().unwrap();
|
||||||
|
@ -204,20 +172,10 @@ fn element_matches_candidate<E: TElement>(element: &E,
|
||||||
Ok(current_styles.primary.clone())
|
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 {
|
fn have_same_presentational_hints<E: TElement>(element: &E, candidate: &E) -> bool {
|
||||||
let mut first = ForgetfulSink::new();
|
let mut first = ForgetfulSink::new();
|
||||||
element.synthesize_presentational_hints_for_legacy_attributes(&mut first);
|
element.synthesize_presentational_hints_for_legacy_attributes(&mut first);
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let mut second = vec![];
|
let mut second = vec![];
|
||||||
candidate.synthesize_presentational_hints_for_legacy_attributes(&mut second);
|
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()
|
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,
|
fn have_same_class<E: TElement>(element: &E,
|
||||||
candidate: &mut StyleSharingCandidate<E>,
|
candidate: &mut StyleSharingCandidate<E>,
|
||||||
candidate_element: &E) -> bool {
|
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.
|
// TODO: These re-match the candidate every time, which is suboptimal.
|
||||||
#[inline]
|
#[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,
|
candidate: &E,
|
||||||
ctx: &SharedStyleContext) -> bool {
|
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]
|
#[inline]
|
||||||
|
@ -387,7 +269,6 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
|
||||||
|
|
||||||
self.cache.insert(StyleSharingCandidate {
|
self.cache.insert(StyleSharingCandidate {
|
||||||
element: unsafe { SendElement::new(*element) },
|
element: unsafe { SendElement::new(*element) },
|
||||||
common_style_affecting_attributes: None,
|
|
||||||
class_attributes: None,
|
class_attributes: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1136,10 +1017,9 @@ pub trait MatchMethods : TElement {
|
||||||
},
|
},
|
||||||
// Too expensive failure, give up, we don't want another
|
// Too expensive failure, give up, we don't want another
|
||||||
// one of these.
|
// one of these.
|
||||||
CacheMiss::CommonStyleAffectingAttributes |
|
|
||||||
CacheMiss::PresHints |
|
CacheMiss::PresHints |
|
||||||
CacheMiss::SiblingRules |
|
CacheMiss::SiblingRules |
|
||||||
CacheMiss::NonCommonAttrRules => break,
|
CacheMiss::AttrRules => break,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ use selectors::{Element, MatchAttr};
|
||||||
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||||
use selectors::matching::matches_complex_selector;
|
use selectors::matching::matches_complex_selector;
|
||||||
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector};
|
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector};
|
||||||
|
use selectors::visitor::SelectorVisitor;
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::sync::Arc;
|
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 {
|
fn combinator_to_restyle_hint(combinator: Option<Combinator>) -> RestyleHint {
|
||||||
match combinator {
|
match combinator {
|
||||||
None => RESTYLE_SELF,
|
None => RESTYLE_SELF,
|
||||||
|
@ -458,6 +475,74 @@ struct Dependency {
|
||||||
sensitivities: Sensitivities,
|
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.
|
/// A set of dependencies for a given stylist.
|
||||||
///
|
///
|
||||||
/// Note that there are measurable perf wins from storing them separately
|
/// Note that there are measurable perf wins from storing them separately
|
||||||
|
@ -476,12 +561,12 @@ pub struct DependencySet {
|
||||||
|
|
||||||
impl DependencySet {
|
impl DependencySet {
|
||||||
fn add_dependency(&mut self, dep: Dependency) {
|
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();
|
let affects_states = !dep.sensitivities.states.is_empty();
|
||||||
|
|
||||||
if affects_attrs && affects_states {
|
if affected_by_attribute && affects_states {
|
||||||
self.common_deps.push(dep)
|
self.common_deps.push(dep)
|
||||||
} else if affects_attrs {
|
} else if affected_by_attribute {
|
||||||
self.attr_deps.push(dep)
|
self.attr_deps.push(dep)
|
||||||
} else {
|
} else {
|
||||||
self.state_deps.push(dep)
|
self.state_deps.push(dep)
|
||||||
|
@ -502,46 +587,6 @@ impl DependencySet {
|
||||||
self.common_deps.len() + self.attr_deps.len() + self.state_deps.len()
|
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.
|
/// Clear this dependency set.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.common_deps.clear();
|
self.common_deps.clear();
|
||||||
|
|
|
@ -7,9 +7,8 @@
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use cssparser::Parser as CssParser;
|
use cssparser::Parser as CssParser;
|
||||||
use matching::{common_style_affecting_attributes, CommonStyleAffectingAttributeMode};
|
|
||||||
use selectors::Element;
|
use selectors::Element;
|
||||||
use selectors::parser::{AttrSelector, SelectorList};
|
use selectors::parser::SelectorList;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use stylesheets::{Origin, Namespaces};
|
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,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,10 +12,10 @@ use cssparser::{Parser as CssParser, ToCss, serialize_identifier};
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use restyle_hints::ElementSnapshot;
|
use restyle_hints::ElementSnapshot;
|
||||||
use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
|
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::{Element, MatchAttrGeneric};
|
||||||
use selectors::matching::StyleRelations;
|
use selectors::matching::StyleRelations;
|
||||||
use selectors::parser::{AttrSelector, SelectorMethods};
|
use selectors::parser::{AttrSelector, SelectorMethods};
|
||||||
|
use selectors::visitor::SelectorVisitor;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -199,10 +199,14 @@ impl ToCss for NonTSPseudoClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorMethods for NonTSPseudoClass {
|
impl SelectorMethods for NonTSPseudoClass {
|
||||||
#[inline]
|
type Impl = SelectorImpl;
|
||||||
fn affects_siblings(&self) -> bool { false }
|
|
||||||
#[inline]
|
|
||||||
fn matches_non_common_style_affecting_attribute(&self) -> bool { false }
|
fn visit<V>(&self, _: &mut V) -> bool
|
||||||
|
where V: SelectorVisitor<Impl = Self::Impl>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
|
@ -251,15 +255,6 @@ impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
type NamespaceUrl = Namespace;
|
type NamespaceUrl = Namespace;
|
||||||
type BorrowedLocalName = LocalName;
|
type BorrowedLocalName = LocalName;
|
||||||
type BorrowedNamespaceUrl = Namespace;
|
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> {
|
impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use properties::{self, CascadeFlags, ComputedValues};
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
use properties::INHERIT_ALL;
|
use properties::INHERIT_ALL;
|
||||||
use properties::PropertyDeclarationBlock;
|
use properties::PropertyDeclarationBlock;
|
||||||
use restyle_hints::{RestyleHint, DependencySet};
|
use restyle_hints::{RestyleHint, DependencySet, SelectorDependencyVisitor};
|
||||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
||||||
use selector_parser::{SelectorImpl, PseudoElement, Snapshot};
|
use selector_parser::{SelectorImpl, PseudoElement, Snapshot};
|
||||||
use selectors::Element;
|
use selectors::Element;
|
||||||
|
@ -117,7 +117,7 @@ pub struct Stylist {
|
||||||
/// Selectors in the page matching elements with non-common style-affecting
|
/// Selectors in the page matching elements with non-common style-affecting
|
||||||
/// attributes.
|
/// attributes.
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
#[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
|
/// This struct holds data which user of Stylist may want to extract
|
||||||
|
@ -169,9 +169,8 @@ impl Stylist {
|
||||||
rule_tree: RuleTree::new(),
|
rule_tree: RuleTree::new(),
|
||||||
state_deps: DependencySet::new(),
|
state_deps: DependencySet::new(),
|
||||||
|
|
||||||
// XXX remember resetting them!
|
|
||||||
sibling_affecting_selectors: vec![],
|
sibling_affecting_selectors: vec![],
|
||||||
non_common_style_affecting_attributes_selectors: vec![]
|
style_affecting_attributes_selectors: vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||||
|
@ -226,7 +225,7 @@ impl Stylist {
|
||||||
self.animations.clear();
|
self.animations.clear();
|
||||||
|
|
||||||
self.sibling_affecting_selectors.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();
|
extra_data.clear_font_faces();
|
||||||
|
|
||||||
|
@ -249,7 +248,7 @@ impl Stylist {
|
||||||
debug!(" - Got {} sibling-affecting selectors",
|
debug!(" - Got {} sibling-affecting selectors",
|
||||||
self.sibling_affecting_selectors.len());
|
self.sibling_affecting_selectors.len());
|
||||||
debug!(" - Got {} non-common-style-attribute-affecting selectors",
|
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",
|
debug!(" - Got {} deps for style-hint calculation",
|
||||||
self.state_deps.len());
|
self.state_deps.len());
|
||||||
|
|
||||||
|
@ -300,13 +299,16 @@ impl Stylist {
|
||||||
self.rules_source_order += 1;
|
self.rules_source_order += 1;
|
||||||
|
|
||||||
for selector in &style_rule.selectors.0 {
|
for selector in &style_rule.selectors.0 {
|
||||||
self.state_deps.note_selector(&selector.complex_selector);
|
let mut visitor =
|
||||||
if selector.affects_siblings() {
|
SelectorDependencyVisitor::new(&mut self.state_deps);
|
||||||
|
selector.visit(&mut visitor);
|
||||||
|
|
||||||
|
if visitor.affects_siblings() {
|
||||||
self.sibling_affecting_selectors.push(selector.clone());
|
self.sibling_affecting_selectors.push(selector.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if selector.matches_non_common_style_affecting_attribute() {
|
if visitor.affected_by_attribute() {
|
||||||
self.non_common_style_affecting_attributes_selectors.push(selector.clone());
|
self.style_affecting_attributes_selectors.push(selector.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -765,9 +767,9 @@ impl Stylist {
|
||||||
///
|
///
|
||||||
/// This is used to test elements and candidates in the style-sharing
|
/// This is used to test elements and candidates in the style-sharing
|
||||||
/// candidate cache.
|
/// 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,
|
element: &E,
|
||||||
candidate: &E) -> bool
|
candidate: &E) -> bool
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
{
|
{
|
||||||
use selectors::matching::StyleRelations;
|
use selectors::matching::StyleRelations;
|
||||||
|
@ -779,7 +781,7 @@ impl Stylist {
|
||||||
//
|
//
|
||||||
// TODO(emilio): Use the bloom filter, since they contain the element's
|
// TODO(emilio): Use the bloom filter, since they contain the element's
|
||||||
// ancestor chain and it's correct for the candidate too.
|
// 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 =
|
let element_matches =
|
||||||
matches_complex_selector(&selector.complex_selector, element,
|
matches_complex_selector(&selector.complex_selector, element,
|
||||||
None, &mut StyleRelations::empty(),
|
None, &mut StyleRelations::empty(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue