mirror of
https://github.com/servo/servo.git
synced 2025-08-14 18:05:36 +01:00
Auto merge of #17439 - bholley:compound_left_to_right, r=SimonSapin
Match compound selectors left-to-right (second try) https://bugzilla.mozilla.org/show_bug.cgi?id=1373800 <!-- 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/17439) <!-- Reviewable:end -->
This commit is contained in:
commit
b211664e87
15 changed files with 482 additions and 303 deletions
|
@ -21,8 +21,8 @@ use rule_tree::CascadeLevel;
|
|||
use selector_parser::{AttrValue, ElementExt, PreExistingComputedValues};
|
||||
use selector_parser::{PseudoClassStringArg, PseudoElement};
|
||||
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
||||
use selectors::sink::Push;
|
||||
use shared_lock::Locked;
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "gecko")] use std::collections::HashMap;
|
||||
|
|
|
@ -310,7 +310,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
|||
Selector::parse(self, input)
|
||||
})?;
|
||||
// Selectors inside `:-moz-any` may not include combinators.
|
||||
if selectors.iter().flat_map(|x| x.iter_raw()).any(|s| s.is_combinator()) {
|
||||
if selectors.iter().flat_map(|x| x.iter_raw_match_order()).any(|s| s.is_combinator()) {
|
||||
return Err(SelectorParseError::UnexpectedIdent("-moz-any".into()).into())
|
||||
}
|
||||
NonTSPseudoClass::MozAny(selectors.into_boxed_slice())
|
||||
|
|
|
@ -76,8 +76,8 @@ use selectors::Element;
|
|||
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity, NamespaceConstraint};
|
||||
use selectors::matching::{ElementSelectorFlags, LocalMatchingContext, MatchingContext};
|
||||
use selectors::matching::{RelevantLinkStatus, VisitedHandlingMode};
|
||||
use selectors::sink::Push;
|
||||
use shared_lock::Locked;
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
|
|
@ -53,7 +53,7 @@ impl fmt::Debug for Invalidation {
|
|||
use cssparser::ToCss;
|
||||
|
||||
f.write_str("Invalidation(")?;
|
||||
for component in self.selector.iter_raw_rev_from(self.offset - 1) {
|
||||
for component in self.selector.iter_raw_parse_order_from(self.offset - 1) {
|
||||
if matches!(*component, Component::Combinator(..)) {
|
||||
break;
|
||||
}
|
||||
|
@ -568,7 +568,7 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator<'a, 'b, E>
|
|||
if matches!(next_combinator, Combinator::PseudoElement) {
|
||||
let pseudo_selector =
|
||||
invalidation.selector
|
||||
.iter_raw_rev_from(next_combinator_offset - 1)
|
||||
.iter_raw_parse_order_from(next_combinator_offset - 1)
|
||||
.next()
|
||||
.unwrap();
|
||||
let pseudo = match *pseudo_selector {
|
||||
|
|
|
@ -126,7 +126,6 @@ pub mod sharing;
|
|||
pub mod stylist;
|
||||
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
|
||||
pub mod sequential;
|
||||
pub mod sink;
|
||||
pub mod str;
|
||||
pub mod style_adjuster;
|
||||
pub mod stylesheet_set;
|
||||
|
|
|
@ -369,15 +369,12 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Searches the selector from right to left, beginning to the left of the
|
||||
/// ::pseudo-element (if any), and ending at the first combinator.
|
||||
/// Searches a compound selector from left to right. If the compound selector
|
||||
/// is a pseudo-element, it's ignored.
|
||||
///
|
||||
/// The first non-None value returned from |f| is returned.
|
||||
///
|
||||
/// Effectively, pseudo-elements are ignored, given only state pseudo-classes
|
||||
/// may appear before them.
|
||||
#[inline(always)]
|
||||
fn find_from_right<F, R>(mut iter: SelectorIter<SelectorImpl>,
|
||||
fn find_from_left<F, R>(mut iter: SelectorIter<SelectorImpl>,
|
||||
mut f: F)
|
||||
-> Option<R>
|
||||
where F: FnMut(&Component<SelectorImpl>) -> Option<R>,
|
||||
|
@ -388,6 +385,8 @@ fn find_from_right<F, R>(mut iter: SelectorIter<SelectorImpl>,
|
|||
}
|
||||
}
|
||||
|
||||
// Effectively, pseudo-elements are ignored, given only state pseudo-classes
|
||||
// may appear before them.
|
||||
if iter.next_sequence() == Some(Combinator::PseudoElement) {
|
||||
for ss in &mut iter {
|
||||
if let Some(r) = f(ss) {
|
||||
|
@ -403,7 +402,7 @@ fn find_from_right<F, R>(mut iter: SelectorIter<SelectorImpl>,
|
|||
#[inline(always)]
|
||||
pub fn get_id_name(iter: SelectorIter<SelectorImpl>)
|
||||
-> Option<Atom> {
|
||||
find_from_right(iter, |ss| {
|
||||
find_from_left(iter, |ss| {
|
||||
// TODO(pradeep): Implement case-sensitivity based on the
|
||||
// document type and quirks mode.
|
||||
if let Component::ID(ref id) = *ss {
|
||||
|
@ -417,7 +416,7 @@ pub fn get_id_name(iter: SelectorIter<SelectorImpl>)
|
|||
#[inline(always)]
|
||||
pub fn get_class_name(iter: SelectorIter<SelectorImpl>)
|
||||
-> Option<Atom> {
|
||||
find_from_right(iter, |ss| {
|
||||
find_from_left(iter, |ss| {
|
||||
// TODO(pradeep): Implement case-sensitivity based on the
|
||||
// document type and quirks mode.
|
||||
if let Component::Class(ref class) = *ss {
|
||||
|
@ -431,7 +430,7 @@ pub fn get_class_name(iter: SelectorIter<SelectorImpl>)
|
|||
#[inline(always)]
|
||||
pub fn get_local_name(iter: SelectorIter<SelectorImpl>)
|
||||
-> Option<LocalNameSelector<SelectorImpl>> {
|
||||
find_from_right(iter, |ss| {
|
||||
find_from_left(iter, |ss| {
|
||||
if let Component::LocalName(ref n) = *ss {
|
||||
return Some(LocalNameSelector {
|
||||
name: n.name.clone(),
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Small helpers to abstract over different containers.
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use smallvec::{Array, SmallVec};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A trait to abstract over a `push` method that may be implemented for
|
||||
/// different kind of types.
|
||||
///
|
||||
/// Used to abstract over `Array`, `SmallVec` and `Vec`, and also to implement a
|
||||
/// type which `push` method does only tweak a byte when we only need to check
|
||||
/// for the presence of something.
|
||||
pub trait Push<T> {
|
||||
/// Push a value into self.
|
||||
fn push(&mut self, value: T);
|
||||
}
|
||||
|
||||
impl<T> Push<T> for Vec<T> {
|
||||
fn push(&mut self, value: T) {
|
||||
Vec::push(self, value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array> Push<A::Item> for SmallVec<A> {
|
||||
fn push(&mut self, value: A::Item) {
|
||||
SmallVec::push(self, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that implements `Push`, but only stores whether it's empty.
|
||||
pub struct ForgetfulSink<T>(bool, PhantomData<T>);
|
||||
|
||||
impl<T> ForgetfulSink<T> {
|
||||
/// Trivially construct a new `ForgetfulSink`.
|
||||
pub fn new() -> Self {
|
||||
ForgetfulSink(true, PhantomData)
|
||||
}
|
||||
|
||||
/// Whether this sink is empty or not.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push<T> for ForgetfulSink<T> {
|
||||
fn push(&mut self, _value: T) {
|
||||
self.0 = false;
|
||||
}
|
||||
}
|
|
@ -31,9 +31,9 @@ use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContex
|
|||
use selectors::matching::AFFECTED_BY_PRESENTATIONAL_HINTS;
|
||||
use selectors::parser::{AncestorHashes, Combinator, Component, Selector, SelectorAndHashes};
|
||||
use selectors::parser::{SelectorIter, SelectorMethods};
|
||||
use selectors::sink::Push;
|
||||
use selectors::visitor::SelectorVisitor;
|
||||
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
use std::fmt::Debug;
|
||||
#[cfg(feature = "servo")]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue