mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +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
|
@ -8,9 +8,10 @@ use cssparser::{Parser, ToCss};
|
|||
use element_state::ElementState;
|
||||
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;
|
||||
use selectors::parser::{AttrSelector, ComplexSelector, SelectorMethods};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
|
@ -152,6 +153,8 @@ macro_rules! pseudo_class_name {
|
|||
#[doc = $s_css]
|
||||
$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) => {
|
||||
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 {
|
||||
/// A pseudo-class is internal if it can only be used inside
|
||||
/// user agent style sheets.
|
||||
|
@ -189,6 +226,7 @@ impl NonTSPseudoClass {
|
|||
match *self {
|
||||
$(NonTSPseudoClass::$name => check_flag!($flags),)*
|
||||
$(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)*
|
||||
NonTSPseudoClass::MozAny(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -207,6 +245,11 @@ impl NonTSPseudoClass {
|
|||
match *self {
|
||||
$(NonTSPseudoClass::$name => flag!($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 {
|
||||
$(NonTSPseudoClass::$name => gecko_type!($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.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct 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();
|
||||
NonTSPseudoClass::$s_name(name)
|
||||
}, )*
|
||||
"-moz-any" => {
|
||||
let selectors = parser.parse_comma_separated(|input| {
|
||||
ComplexSelector::parse(self, input)
|
||||
})?;
|
||||
NonTSPseudoClass::MozAny(selectors)
|
||||
}
|
||||
_ => return Err(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ use properties::PropertyDeclarationBlock;
|
|||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||
use selector_parser::{ElementExt, Snapshot};
|
||||
use selectors::Element;
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||
use servo_url::ServoUrl;
|
||||
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 {
|
||||
// https://github.com/servo/servo/issues/8718
|
||||
NonTSPseudoClass::AnyLink => unsafe { Gecko_IsLink(self.0) },
|
||||
|
@ -667,7 +670,10 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
NonTSPseudoClass::MozBrowserFrame => unsafe {
|
||||
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> {
|
||||
#[inline]
|
||||
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]
|
||||
|
|
|
@ -269,14 +269,17 @@ impl<'a, E> MatchAttr for ElementWrapper<'a, E>
|
|||
impl<'a, E> Element for ElementWrapper<'a, E>
|
||||
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);
|
||||
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 {
|
||||
match self.snapshot.and_then(|s| s.state()) {
|
||||
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 {
|
||||
match *sel {
|
||||
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::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
|
||||
use selectors::{Element, MatchAttrGeneric};
|
||||
use selectors::parser::AttrSelector;
|
||||
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||
use selectors::parser::{AttrSelector, SelectorMethods};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
|
@ -60,7 +61,6 @@ impl ToCss for PseudoElement {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl PseudoElement {
|
||||
/// Whether the current pseudo element is :before or :after.
|
||||
#[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 {
|
||||
/// Gets a given state flag for this pseudo-class. This is used to do
|
||||
/// 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 {
|
||||
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]
|
||||
|
|
|
@ -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::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
||||
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
|
||||
use selectors::parser::SelectorMethods;
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
use std::borrow::Borrow;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue