mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #15966 - mbrubeck:any, r=emilio
Bug 1340683 - stylo: Implement the :-moz-any pseudo-class Adds support for the non-standard [:-moz-any](https://developer.mozilla.org/en-US/docs/Web/CSS/:any) selector. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix https://bugzilla.mozilla.org/show_bug.cgi?id=1340683 - [x] These changes do not require tests because they are gecko-only <!-- 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/15966) <!-- Reviewable:end -->
This commit is contained in:
commit
0a747e23c6
10 changed files with 146 additions and 40 deletions
|
@ -86,7 +86,7 @@ use parking_lot::RwLock;
|
||||||
use ref_filter_map::ref_filter_map;
|
use ref_filter_map::ref_filter_map;
|
||||||
use script_layout_interface::message::ReflowQueryType;
|
use script_layout_interface::message::ReflowQueryType;
|
||||||
use script_thread::Runnable;
|
use script_thread::Runnable;
|
||||||
use selectors::matching::{ElementSelectorFlags, matches};
|
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches};
|
||||||
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
|
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
|
||||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
|
@ -2392,7 +2392,10 @@ impl<'a> ::selectors::Element for Root<Element> {
|
||||||
self.namespace()
|
self.namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool {
|
fn match_non_ts_pseudo_class(&self,
|
||||||
|
pseudo_class: &NonTSPseudoClass,
|
||||||
|
_: &mut StyleRelations,
|
||||||
|
_: &mut ElementSelectorFlags) -> bool {
|
||||||
match *pseudo_class {
|
match *pseudo_class {
|
||||||
// https://github.com/servo/servo/issues/8718
|
// https://github.com/servo/servo/issues/8718
|
||||||
NonTSPseudoClass::Link |
|
NonTSPseudoClass::Link |
|
||||||
|
|
|
@ -50,7 +50,7 @@ use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, Truste
|
||||||
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
|
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
|
||||||
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
|
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
|
||||||
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||||
use selectors::matching::ElementSelectorFlags;
|
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
@ -611,7 +611,10 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
self.element.namespace()
|
self.element.namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool {
|
fn match_non_ts_pseudo_class(&self,
|
||||||
|
pseudo_class: &NonTSPseudoClass,
|
||||||
|
_: &mut StyleRelations,
|
||||||
|
_: &mut ElementSelectorFlags) -> bool {
|
||||||
match *pseudo_class {
|
match *pseudo_class {
|
||||||
// https://github.com/servo/servo/issues/8718
|
// https://github.com/servo/servo/issues/8718
|
||||||
NonTSPseudoClass::Link |
|
NonTSPseudoClass::Link |
|
||||||
|
@ -1106,7 +1109,10 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
|
||||||
self.element.get_namespace()
|
self.element.get_namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class(&self, _: &NonTSPseudoClass) -> bool {
|
fn match_non_ts_pseudo_class(&self,
|
||||||
|
_: &NonTSPseudoClass,
|
||||||
|
_: &mut StyleRelations,
|
||||||
|
_: &mut ElementSelectorFlags) -> bool {
|
||||||
// NB: This could maybe be implemented
|
// NB: This could maybe be implemented
|
||||||
warn!("ServoThreadSafeLayoutElement::match_non_ts_pseudo_class called");
|
warn!("ServoThreadSafeLayoutElement::match_non_ts_pseudo_class called");
|
||||||
false
|
false
|
||||||
|
|
|
@ -413,7 +413,7 @@ fn matches_simple_selector<E>(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
SimpleSelector::NonTSPseudoClass(ref pc) => {
|
SimpleSelector::NonTSPseudoClass(ref pc) => {
|
||||||
relation_if!(element.match_non_ts_pseudo_class(pc),
|
relation_if!(element.match_non_ts_pseudo_class(pc, relations, flags),
|
||||||
AFFECTED_BY_STATE)
|
AFFECTED_BY_STATE)
|
||||||
}
|
}
|
||||||
SimpleSelector::FirstChild => {
|
SimpleSelector::FirstChild => {
|
||||||
|
|
|
@ -49,7 +49,7 @@ macro_rules! with_all_bounds {
|
||||||
|
|
||||||
/// non tree-structural pseudo-classes
|
/// non tree-structural pseudo-classes
|
||||||
/// (see: https://drafts.csswg.org/selectors/#structural-pseudos)
|
/// (see: https://drafts.csswg.org/selectors/#structural-pseudos)
|
||||||
type NonTSPseudoClass: $($CommonBounds)* + Sized + ToCss;
|
type NonTSPseudoClass: $($CommonBounds)* + Sized + ToCss + SelectorMethods;
|
||||||
|
|
||||||
/// pseudo-elements
|
/// pseudo-elements
|
||||||
type PseudoElement: $($CommonBounds)* + Sized + ToCss;
|
type PseudoElement: $($CommonBounds)* + Sized + ToCss;
|
||||||
|
@ -120,7 +120,7 @@ pub trait Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
pub struct SelectorList<Impl: SelectorImpl>(pub Vec<Selector<Impl>>);
|
pub struct SelectorList<Impl: SelectorImpl>(pub Vec<Selector<Impl>>);
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> SelectorList<Impl> {
|
impl<Impl: SelectorImpl> SelectorList<Impl> {
|
||||||
|
@ -135,7 +135,7 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||||
pub struct Selector<Impl: SelectorImpl> {
|
pub struct Selector<Impl: SelectorImpl> {
|
||||||
pub complex_selector: Arc<ComplexSelector<Impl>>,
|
pub complex_selector: Arc<ComplexSelector<Impl>>,
|
||||||
pub pseudo_element: Option<Impl::PseudoElement>,
|
pub pseudo_element: Option<Impl::PseudoElement>,
|
||||||
|
@ -159,6 +159,8 @@ fn affects_sibling<Impl: SelectorImpl>(simple_selector: &SimpleSelector<Impl>) -
|
||||||
SimpleSelector::LastOfType |
|
SimpleSelector::LastOfType |
|
||||||
SimpleSelector::OnlyOfType => true,
|
SimpleSelector::OnlyOfType => true,
|
||||||
|
|
||||||
|
SimpleSelector::NonTSPseudoClass(ref pseudo_class) => pseudo_class.affects_siblings(),
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,28 +182,36 @@ fn matches_non_common_style_affecting_attribute<Impl: SelectorImpl>(simple_selec
|
||||||
SimpleSelector::AttrSuffixMatch(..) |
|
SimpleSelector::AttrSuffixMatch(..) |
|
||||||
SimpleSelector::AttrSubstringMatch(..) => true,
|
SimpleSelector::AttrSubstringMatch(..) => true,
|
||||||
|
|
||||||
|
SimpleSelector::NonTSPseudoClass(ref pseudo_class) =>
|
||||||
|
pseudo_class.matches_non_common_style_affecting_attribute(),
|
||||||
|
|
||||||
// This deliberately includes Attr*NeverMatch
|
// This deliberately includes Attr*NeverMatch
|
||||||
// which never match regardless of element attributes.
|
// which never match regardless of element attributes.
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> Selector<Impl> {
|
pub trait SelectorMethods {
|
||||||
|
fn affects_siblings(&self) -> bool;
|
||||||
|
fn matches_non_common_style_affecting_attribute(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Impl: SelectorImpl> SelectorMethods for Selector<Impl> {
|
||||||
/// Whether this selector, if matching on a set of siblings, could affect
|
/// Whether this selector, if matching on a set of siblings, could affect
|
||||||
/// other sibling's style.
|
/// other sibling's style.
|
||||||
pub fn affects_siblings(&self) -> bool {
|
fn affects_siblings(&self) -> bool {
|
||||||
self.complex_selector.affects_siblings()
|
self.complex_selector.affects_siblings()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches_non_common_style_affecting_attribute(&self) -> bool {
|
fn matches_non_common_style_affecting_attribute(&self) -> bool {
|
||||||
self.complex_selector.matches_non_common_style_affecting_attribute()
|
self.complex_selector.matches_non_common_style_affecting_attribute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> ComplexSelector<Impl> {
|
impl<Impl: SelectorImpl> SelectorMethods for ComplexSelector<Impl> {
|
||||||
/// Whether this complex selector, if matching on a set of siblings,
|
/// Whether this complex selector, if matching on a set of siblings,
|
||||||
/// could affect other sibling's style.
|
/// could affect other sibling's style.
|
||||||
pub fn affects_siblings(&self) -> bool {
|
fn affects_siblings(&self) -> bool {
|
||||||
match self.next {
|
match self.next {
|
||||||
Some((_, Combinator::NextSibling)) |
|
Some((_, Combinator::NextSibling)) |
|
||||||
Some((_, Combinator::LaterSibling)) => return true,
|
Some((_, Combinator::LaterSibling)) => return true,
|
||||||
|
@ -214,7 +224,7 @@ impl<Impl: SelectorImpl> ComplexSelector<Impl> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches_non_common_style_affecting_attribute(&self) -> bool {
|
fn matches_non_common_style_affecting_attribute(&self) -> bool {
|
||||||
match self.compound_selector.last() {
|
match self.compound_selector.last() {
|
||||||
Some(ref selector) => matches_non_common_style_affecting_attribute(selector),
|
Some(ref selector) => matches_non_common_style_affecting_attribute(selector),
|
||||||
None => false,
|
None => false,
|
||||||
|
@ -714,18 +724,18 @@ fn parse_complex_selector_and_pseudo_element<P, Impl>(
|
||||||
Ok((complex, pseudo_element))
|
Ok((complex, pseudo_element))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_complex_selector<P, Impl>(
|
impl<Impl: SelectorImpl> ComplexSelector<Impl> {
|
||||||
parser: &P,
|
/// Parse a complex selector.
|
||||||
input: &mut CssParser)
|
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()>
|
||||||
-> Result<ComplexSelector<Impl>, ()>
|
where P: Parser<Impl=Impl>
|
||||||
where P: Parser<Impl=Impl>, Impl: SelectorImpl
|
{
|
||||||
{
|
let (complex, pseudo_element) =
|
||||||
let (complex, pseudo_element) =
|
parse_complex_selector_and_pseudo_element(parser, input)?;
|
||||||
parse_complex_selector_and_pseudo_element(parser, input)?;
|
if pseudo_element.is_some() {
|
||||||
if pseudo_element.is_some() {
|
return Err(())
|
||||||
return Err(())
|
}
|
||||||
|
Ok(complex)
|
||||||
}
|
}
|
||||||
Ok(complex)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// * `Err(())`: Invalid selector, abort
|
/// * `Err(())`: Invalid selector, abort
|
||||||
|
@ -934,7 +944,7 @@ fn parse_negation<P, Impl>(parser: &P,
|
||||||
-> Result<SimpleSelector<Impl>, ()>
|
-> Result<SimpleSelector<Impl>, ()>
|
||||||
where P: Parser<Impl=Impl>, Impl: SelectorImpl
|
where P: Parser<Impl=Impl>, Impl: SelectorImpl
|
||||||
{
|
{
|
||||||
input.parse_comma_separated(|input| parse_complex_selector(parser, input).map(Arc::new))
|
input.parse_comma_separated(|input| ComplexSelector::parse(parser, input).map(Arc::new))
|
||||||
.map(SimpleSelector::Negation)
|
.map(SimpleSelector::Negation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,6 +1174,11 @@ pub mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SelectorMethods for PseudoClass {
|
||||||
|
fn affects_siblings(&self) -> bool { false }
|
||||||
|
fn matches_non_common_style_affecting_attribute(&self) -> bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct DummySelectorImpl;
|
pub struct DummySelectorImpl;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
||||||
//! style.
|
//! style.
|
||||||
|
|
||||||
|
use matching::{ElementSelectorFlags, StyleRelations};
|
||||||
use parser::{AttrSelector, SelectorImpl};
|
use parser::{AttrSelector, SelectorImpl};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
|
||||||
|
@ -138,7 +139,10 @@ pub trait Element: MatchAttr + Sized {
|
||||||
fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
|
fn get_local_name(&self) -> &<Self::Impl as SelectorImpl>::BorrowedLocalName;
|
||||||
fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
|
fn get_namespace(&self) -> &<Self::Impl as SelectorImpl>::BorrowedNamespaceUrl;
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class(&self, pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass) -> bool;
|
fn match_non_ts_pseudo_class(&self,
|
||||||
|
pc: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
|
||||||
|
relations: &mut StyleRelations,
|
||||||
|
flags: &mut ElementSelectorFlags) -> bool;
|
||||||
|
|
||||||
fn get_id(&self) -> Option<<Self::Impl as SelectorImpl>::Identifier>;
|
fn get_id(&self) -> Option<<Self::Impl as SelectorImpl>::Identifier>;
|
||||||
fn has_class(&self, name: &<Self::Impl as SelectorImpl>::ClassName) -> bool;
|
fn has_class(&self, name: &<Self::Impl as SelectorImpl>::ClassName) -> bool;
|
||||||
|
|
|
@ -8,9 +8,10 @@ use cssparser::{Parser, ToCss};
|
||||||
use element_state::ElementState;
|
use element_state::ElementState;
|
||||||
use gecko_bindings::structs::CSSPseudoClassType;
|
use gecko_bindings::structs::CSSPseudoClassType;
|
||||||
use gecko_bindings::structs::nsIAtom;
|
use gecko_bindings::structs::nsIAtom;
|
||||||
|
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 selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
|
||||||
use selectors::parser::AttrSelector;
|
use selectors::parser::{AttrSelector, ComplexSelector, SelectorMethods};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -152,6 +153,8 @@ macro_rules! pseudo_class_name {
|
||||||
#[doc = $s_css]
|
#[doc = $s_css]
|
||||||
$s_name(Box<str>),
|
$s_name(Box<str>),
|
||||||
)*
|
)*
|
||||||
|
/// The non-standard `:-moz-any` pseudo-class.
|
||||||
|
MozAny(Vec<ComplexSelector<SelectorImpl>>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,6 +170,17 @@ impl ToCss for NonTSPseudoClass {
|
||||||
$(NonTSPseudoClass::$s_name(ref s) => {
|
$(NonTSPseudoClass::$s_name(ref s) => {
|
||||||
return dest.write_str(&format!(":{}({})", $s_css, s))
|
return dest.write_str(&format!(":{}({})", $s_css, s))
|
||||||
}, )*
|
}, )*
|
||||||
|
NonTSPseudoClass::MozAny(ref selectors) => {
|
||||||
|
dest.write_str(":-moz-any(")?;
|
||||||
|
let mut iter = selectors.iter();
|
||||||
|
let first = iter.next().expect(":-moz-any must have at least 1 selector");
|
||||||
|
first.to_css(dest)?;
|
||||||
|
for selector in iter {
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
selector.to_css(dest)?;
|
||||||
|
}
|
||||||
|
return dest.write_str(")")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +189,29 @@ 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())
|
||||||
|
}
|
||||||
|
_ => 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
/// A pseudo-class is internal if it can only be used inside
|
/// A pseudo-class is internal if it can only be used inside
|
||||||
/// user agent style sheets.
|
/// user agent style sheets.
|
||||||
|
@ -189,6 +226,7 @@ impl NonTSPseudoClass {
|
||||||
match *self {
|
match *self {
|
||||||
$(NonTSPseudoClass::$name => check_flag!($flags),)*
|
$(NonTSPseudoClass::$name => check_flag!($flags),)*
|
||||||
$(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)*
|
$(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)*
|
||||||
|
NonTSPseudoClass::MozAny(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,6 +245,11 @@ impl NonTSPseudoClass {
|
||||||
match *self {
|
match *self {
|
||||||
$(NonTSPseudoClass::$name => flag!($state),)*
|
$(NonTSPseudoClass::$name => flag!($state),)*
|
||||||
$(NonTSPseudoClass::$s_name(..) => flag!($s_state),)*
|
$(NonTSPseudoClass::$s_name(..) => flag!($s_state),)*
|
||||||
|
NonTSPseudoClass::MozAny(ref selectors) => {
|
||||||
|
selectors.iter().fold(ElementState::empty(), |state, s| {
|
||||||
|
state | complex_selector_to_state(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,6 +269,7 @@ impl NonTSPseudoClass {
|
||||||
match *self {
|
match *self {
|
||||||
$(NonTSPseudoClass::$name => gecko_type!($gecko_type),)*
|
$(NonTSPseudoClass::$name => gecko_type!($gecko_type),)*
|
||||||
$(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)*
|
$(NonTSPseudoClass::$s_name(..) => gecko_type!($s_gecko_type),)*
|
||||||
|
NonTSPseudoClass::MozAny(_) => gecko_type!(any),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +278,7 @@ impl NonTSPseudoClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The dummy struct we use to implement our selector parsing.
|
/// The dummy struct we use to implement our selector parsing.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct SelectorImpl;
|
pub struct SelectorImpl;
|
||||||
|
|
||||||
impl ::selectors::SelectorImpl for SelectorImpl {
|
impl ::selectors::SelectorImpl for SelectorImpl {
|
||||||
|
@ -293,6 +337,12 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
||||||
let name = String::from(parser.expect_ident_or_string()?).into_boxed_str();
|
let name = String::from(parser.expect_ident_or_string()?).into_boxed_str();
|
||||||
NonTSPseudoClass::$s_name(name)
|
NonTSPseudoClass::$s_name(name)
|
||||||
}, )*
|
}, )*
|
||||||
|
"-moz-any" => {
|
||||||
|
let selectors = parser.parse_comma_separated(|input| {
|
||||||
|
ComplexSelector::parse(self, input)
|
||||||
|
})?;
|
||||||
|
NonTSPseudoClass::MozAny(selectors)
|
||||||
|
}
|
||||||
_ => return Err(())
|
_ => return Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ use properties::PropertyDeclarationBlock;
|
||||||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||||
use selector_parser::{ElementExt, Snapshot};
|
use selector_parser::{ElementExt, Snapshot};
|
||||||
use selectors::Element;
|
use selectors::Element;
|
||||||
use selectors::matching::ElementSelectorFlags;
|
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
||||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
|
@ -637,7 +637,10 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool {
|
fn match_non_ts_pseudo_class(&self,
|
||||||
|
pseudo_class: &NonTSPseudoClass,
|
||||||
|
relations: &mut StyleRelations,
|
||||||
|
flags: &mut ElementSelectorFlags) -> bool {
|
||||||
match *pseudo_class {
|
match *pseudo_class {
|
||||||
// https://github.com/servo/servo/issues/8718
|
// https://github.com/servo/servo/issues/8718
|
||||||
NonTSPseudoClass::AnyLink => unsafe { Gecko_IsLink(self.0) },
|
NonTSPseudoClass::AnyLink => unsafe { Gecko_IsLink(self.0) },
|
||||||
|
@ -667,7 +670,10 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
NonTSPseudoClass::MozBrowserFrame => unsafe {
|
NonTSPseudoClass::MozBrowserFrame => unsafe {
|
||||||
Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
|
Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
|
||||||
},
|
},
|
||||||
_ => false
|
NonTSPseudoClass::MozSystemMetric(_) => false,
|
||||||
|
NonTSPseudoClass::MozAny(ref sels) => {
|
||||||
|
sels.iter().any(|s| matches_complex_selector(s, self, None, relations, flags))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,7 +811,9 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
|
||||||
impl<'le> ElementExt for GeckoElement<'le> {
|
impl<'le> ElementExt for GeckoElement<'le> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink)
|
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
|
||||||
|
&mut StyleRelations::empty(),
|
||||||
|
&mut ElementSelectorFlags::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -269,14 +269,17 @@ impl<'a, E> MatchAttr for ElementWrapper<'a, E>
|
||||||
impl<'a, E> Element for ElementWrapper<'a, E>
|
impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
{
|
{
|
||||||
fn match_non_ts_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool {
|
fn match_non_ts_pseudo_class(&self,
|
||||||
|
pseudo_class: &NonTSPseudoClass,
|
||||||
|
relations: &mut StyleRelations,
|
||||||
|
flags: &mut ElementSelectorFlags) -> bool {
|
||||||
let flag = SelectorImpl::pseudo_class_state_flag(pseudo_class);
|
let flag = SelectorImpl::pseudo_class_state_flag(pseudo_class);
|
||||||
if flag == ElementState::empty() {
|
if flag == ElementState::empty() {
|
||||||
self.element.match_non_ts_pseudo_class(pseudo_class)
|
self.element.match_non_ts_pseudo_class(pseudo_class, relations, flags)
|
||||||
} else {
|
} else {
|
||||||
match self.snapshot.and_then(|s| s.state()) {
|
match self.snapshot.and_then(|s| s.state()) {
|
||||||
Some(snapshot_state) => snapshot_state.contains(flag),
|
Some(snapshot_state) => snapshot_state.contains(flag),
|
||||||
_ => self.element.match_non_ts_pseudo_class(pseudo_class)
|
_ => self.element.match_non_ts_pseudo_class(pseudo_class, relations, flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,6 +350,13 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the union of any `ElementState` flags for components of a `ComplexSelector`
|
||||||
|
pub fn complex_selector_to_state(sel: &ComplexSelector<SelectorImpl>) -> ElementState {
|
||||||
|
sel.compound_selector.iter().fold(ElementState::empty(), |state, s| {
|
||||||
|
state | selector_to_state(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn selector_to_state(sel: &SimpleSelector<SelectorImpl>) -> ElementState {
|
fn selector_to_state(sel: &SimpleSelector<SelectorImpl>) -> ElementState {
|
||||||
match *sel {
|
match *sel {
|
||||||
SimpleSelector::NonTSPseudoClass(ref pc) => SelectorImpl::pseudo_class_state_flag(pc),
|
SimpleSelector::NonTSPseudoClass(ref pc) => SelectorImpl::pseudo_class_state_flag(pc),
|
||||||
|
|
|
@ -14,7 +14,8 @@ 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 selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
|
||||||
use selectors::{Element, MatchAttrGeneric};
|
use selectors::{Element, MatchAttrGeneric};
|
||||||
use selectors::parser::AttrSelector;
|
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||||
|
use selectors::parser::{AttrSelector, SelectorMethods};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -60,7 +61,6 @@ impl ToCss for PseudoElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl PseudoElement {
|
impl PseudoElement {
|
||||||
/// Whether the current pseudo element is :before or :after.
|
/// Whether the current pseudo element is :before or :after.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -150,6 +150,13 @@ 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 }
|
||||||
|
}
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
/// Gets a given state flag for this pseudo-class. This is used to do
|
/// Gets a given state flag for this pseudo-class. This is used to do
|
||||||
/// selector matching, and it's set from the DOM.
|
/// selector matching, and it's set from the DOM.
|
||||||
|
@ -450,7 +457,9 @@ impl MatchAttrGeneric for ServoElementSnapshot {
|
||||||
|
|
||||||
impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
|
impl<E: Element<Impl=SelectorImpl> + Debug> ElementExt for E {
|
||||||
fn is_link(&self) -> bool {
|
fn is_link(&self) -> bool {
|
||||||
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink)
|
self.match_non_ts_pseudo_class(&NonTSPseudoClass::AnyLink,
|
||||||
|
&mut StyleRelations::empty(),
|
||||||
|
&mut ElementSelectorFlags::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -27,6 +27,7 @@ use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
|
||||||
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
||||||
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
||||||
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
|
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
|
||||||
|
use selectors::parser::SelectorMethods;
|
||||||
use sink::Push;
|
use sink::Push;
|
||||||
use smallvec::VecLike;
|
use smallvec::VecLike;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue