1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5 use crate::attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
6 use crate::attr::{NamespaceConstraint, ParsedAttrSelectorOperation};
7 use crate::attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE};
8 use crate::bloom::BLOOM_HASH_MASK;
9 use crate::builder::{SelectorBuilder, SelectorFlags, SpecificityAndFlags};
10 use crate::context::QuirksMode;
11 use crate::sink::Push;
12 pub use crate::visitor::SelectorVisitor;
13 use cssparser::parse_nth;
14 use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
15 use cssparser::{CowRcStr, Delimiter, SourceLocation};
16 use cssparser::{Parser as CssParser, ToCss, Token};
17 use precomputed_hash::PrecomputedHash;
18 use servo_arc::ThinArc;
19 use smallvec::SmallVec;
20 use std::borrow::{Borrow, Cow};
21 use std::fmt::{self, Debug};
22 use std::iter::Rev;
23 use std::slice;
24
25 /// A trait that represents a pseudo-element.
26 pub trait PseudoElement: Sized + ToCss {
27 /// The `SelectorImpl` this pseudo-element is used for.
28 type Impl: SelectorImpl;
29
30 /// Whether the pseudo-element supports a given state selector to the right
31 /// of it.
accepts_state_pseudo_classes(&self) -> bool32 fn accepts_state_pseudo_classes(&self) -> bool {
33 false
34 }
35
36 /// Whether this pseudo-element is valid after a ::slotted(..) pseudo.
valid_after_slotted(&self) -> bool37 fn valid_after_slotted(&self) -> bool {
38 false
39 }
40 }
41
42 /// A trait that represents a pseudo-class.
43 pub trait NonTSPseudoClass: Sized + ToCss {
44 /// The `SelectorImpl` this pseudo-element is used for.
45 type Impl: SelectorImpl;
46
47 /// Whether this pseudo-class is :active or :hover.
is_active_or_hover(&self) -> bool48 fn is_active_or_hover(&self) -> bool;
49
50 /// Whether this pseudo-class belongs to:
51 ///
52 /// https://drafts.csswg.org/selectors-4/#useraction-pseudos
is_user_action_state(&self) -> bool53 fn is_user_action_state(&self) -> bool;
54
visit<V>(&self, _visitor: &mut V) -> bool where V: SelectorVisitor<Impl = Self::Impl>,55 fn visit<V>(&self, _visitor: &mut V) -> bool
56 where
57 V: SelectorVisitor<Impl = Self::Impl>,
58 {
59 true
60 }
61 }
62
63 /// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
64 /// Cow::Owned if `s` had to be converted into ASCII lowercase.
to_ascii_lowercase(s: &str) -> Cow<str>65 fn to_ascii_lowercase(s: &str) -> Cow<str> {
66 if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
67 let mut string = s.to_owned();
68 string[first_uppercase..].make_ascii_lowercase();
69 string.into()
70 } else {
71 s.into()
72 }
73 }
74
75 bitflags! {
76 /// Flags that indicate at which point of parsing a selector are we.
77 struct SelectorParsingState: u8 {
78 /// Whether we should avoid adding default namespaces to selectors that
79 /// aren't type or universal selectors.
80 const SKIP_DEFAULT_NAMESPACE = 1 << 0;
81
82 /// Whether we've parsed a ::slotted() pseudo-element already.
83 ///
84 /// If so, then we can only parse a subset of pseudo-elements, and
85 /// whatever comes after them if so.
86 const AFTER_SLOTTED = 1 << 1;
87 /// Whether we've parsed a ::part() pseudo-element already.
88 ///
89 /// If so, then we can only parse a subset of pseudo-elements, and
90 /// whatever comes after them if so.
91 const AFTER_PART = 1 << 2;
92 /// Whether we've parsed a pseudo-element (as in, an
93 /// `Impl::PseudoElement` thus not accounting for `::slotted` or
94 /// `::part`) already.
95 ///
96 /// If so, then other pseudo-elements and most other selectors are
97 /// disallowed.
98 const AFTER_PSEUDO_ELEMENT = 1 << 3;
99 /// Whether we've parsed a non-stateful pseudo-element (again, as-in
100 /// `Impl::PseudoElement`) already. If so, then other pseudo-classes are
101 /// disallowed. If this flag is set, `AFTER_PSEUDO_ELEMENT` must be set
102 /// as well.
103 const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
104
105 /// Whether we are after any of the pseudo-like things.
106 const AFTER_PSEUDO = Self::AFTER_PART.bits | Self::AFTER_SLOTTED.bits | Self::AFTER_PSEUDO_ELEMENT.bits;
107
108 /// Whether we explicitly disallow combinators.
109 const DISALLOW_COMBINATORS = 1 << 5;
110
111 /// Whether we explicitly disallow pseudo-element-like things.
112 const DISALLOW_PSEUDOS = 1 << 6;
113 }
114 }
115
116 impl SelectorParsingState {
117 #[inline]
allows_pseudos(self) -> bool118 fn allows_pseudos(self) -> bool {
119 // NOTE(emilio): We allow pseudos after ::part and such.
120 !self.intersects(Self::AFTER_PSEUDO_ELEMENT | Self::DISALLOW_PSEUDOS)
121 }
122
123 #[inline]
allows_slotted(self) -> bool124 fn allows_slotted(self) -> bool {
125 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
126 }
127
128 #[inline]
allows_part(self) -> bool129 fn allows_part(self) -> bool {
130 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
131 }
132
133 // TODO(emilio): Maybe some of these should be allowed, but this gets us on
134 // the safe side for now, matching previous behavior. Gotta be careful with
135 // the ones like :-moz-any, which allow nested selectors but don't carry the
136 // state, and so on.
137 #[inline]
allows_custom_functional_pseudo_classes(self) -> bool138 fn allows_custom_functional_pseudo_classes(self) -> bool {
139 !self.intersects(Self::AFTER_PSEUDO)
140 }
141
142 #[inline]
allows_non_functional_pseudo_classes(self) -> bool143 fn allows_non_functional_pseudo_classes(self) -> bool {
144 !self.intersects(Self::AFTER_SLOTTED | Self::AFTER_NON_STATEFUL_PSEUDO_ELEMENT)
145 }
146
147 #[inline]
allows_tree_structural_pseudo_classes(self) -> bool148 fn allows_tree_structural_pseudo_classes(self) -> bool {
149 !self.intersects(Self::AFTER_PSEUDO)
150 }
151
152 #[inline]
allows_combinators(self) -> bool153 fn allows_combinators(self) -> bool {
154 !self.intersects(Self::DISALLOW_COMBINATORS)
155 }
156 }
157
158 pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>;
159
160 #[derive(Clone, Debug, PartialEq)]
161 pub enum SelectorParseErrorKind<'i> {
162 NoQualifiedNameInAttributeSelector(Token<'i>),
163 EmptySelector,
164 DanglingCombinator,
165 NonCompoundSelector,
166 NonPseudoElementAfterSlotted,
167 InvalidPseudoElementAfterSlotted,
168 InvalidPseudoElementInsideWhere,
169 InvalidState,
170 UnexpectedTokenInAttributeSelector(Token<'i>),
171 PseudoElementExpectedColon(Token<'i>),
172 PseudoElementExpectedIdent(Token<'i>),
173 NoIdentForPseudo(Token<'i>),
174 UnsupportedPseudoClassOrElement(CowRcStr<'i>),
175 UnexpectedIdent(CowRcStr<'i>),
176 ExpectedNamespace(CowRcStr<'i>),
177 ExpectedBarInAttr(Token<'i>),
178 BadValueInAttr(Token<'i>),
179 InvalidQualNameInAttr(Token<'i>),
180 ExplicitNamespaceUnexpectedToken(Token<'i>),
181 ClassNeedsIdent(Token<'i>),
182 }
183
184 macro_rules! with_all_bounds {
185 (
186 [ $( $InSelector: tt )* ]
187 [ $( $CommonBounds: tt )* ]
188 [ $( $FromStr: tt )* ]
189 ) => {
190 /// This trait allows to define the parser implementation in regards
191 /// of pseudo-classes/elements
192 ///
193 /// NB: We need Clone so that we can derive(Clone) on struct with that
194 /// are parameterized on SelectorImpl. See
195 /// <https://github.com/rust-lang/rust/issues/26925>
196 pub trait SelectorImpl: Clone + Debug + Sized + 'static {
197 type ExtraMatchingData: Sized + Default + 'static;
198 type AttrValue: $($InSelector)*;
199 type Identifier: $($InSelector)*;
200 type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
201 type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
202 type NamespacePrefix: $($InSelector)* + Default;
203 type BorrowedNamespaceUrl: ?Sized + Eq;
204 type BorrowedLocalName: ?Sized + Eq;
205
206 /// non tree-structural pseudo-classes
207 /// (see: https://drafts.csswg.org/selectors/#structural-pseudos)
208 type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass<Impl = Self>;
209
210 /// pseudo-elements
211 type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
212
213 /// Whether attribute hashes should be collected for filtering
214 /// purposes.
215 fn should_collect_attr_hash(_name: &Self::LocalName) -> bool {
216 false
217 }
218 }
219 }
220 }
221
222 macro_rules! with_bounds {
223 ( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
224 with_all_bounds! {
225 [$($CommonBounds)* + $($FromStr)* + ToCss]
226 [$($CommonBounds)*]
227 [$($FromStr)*]
228 }
229 }
230 }
231
232 with_bounds! {
233 [Clone + Eq]
234 [for<'a> From<&'a str>]
235 }
236
237 pub trait Parser<'i> {
238 type Impl: SelectorImpl;
239 type Error: 'i + From<SelectorParseErrorKind<'i>>;
240
241 /// Whether to parse the `::slotted()` pseudo-element.
parse_slotted(&self) -> bool242 fn parse_slotted(&self) -> bool {
243 false
244 }
245
246 /// Whether to parse the `::part()` pseudo-element.
parse_part(&self) -> bool247 fn parse_part(&self) -> bool {
248 false
249 }
250
251 /// Whether to parse the `:where` pseudo-class.
parse_is_and_where(&self) -> bool252 fn parse_is_and_where(&self) -> bool {
253 false
254 }
255
256 /// Whether the given function name is an alias for the `:is()` function.
is_is_alias(&self, _name: &str) -> bool257 fn is_is_alias(&self, _name: &str) -> bool {
258 false
259 }
260
261 /// Whether to parse the `:host` pseudo-class.
parse_host(&self) -> bool262 fn parse_host(&self) -> bool {
263 false
264 }
265
266 /// This function can return an "Err" pseudo-element in order to support CSS2.1
267 /// pseudo-elements.
parse_non_ts_pseudo_class( &self, location: SourceLocation, name: CowRcStr<'i>, ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>>268 fn parse_non_ts_pseudo_class(
269 &self,
270 location: SourceLocation,
271 name: CowRcStr<'i>,
272 ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
273 Err(
274 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
275 name,
276 )),
277 )
278 }
279
parse_non_ts_functional_pseudo_class<'t>( &self, name: CowRcStr<'i>, arguments: &mut CssParser<'i, 't>, ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>>280 fn parse_non_ts_functional_pseudo_class<'t>(
281 &self,
282 name: CowRcStr<'i>,
283 arguments: &mut CssParser<'i, 't>,
284 ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
285 Err(
286 arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
287 name,
288 )),
289 )
290 }
291
parse_pseudo_element( &self, location: SourceLocation, name: CowRcStr<'i>, ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>>292 fn parse_pseudo_element(
293 &self,
294 location: SourceLocation,
295 name: CowRcStr<'i>,
296 ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
297 Err(
298 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
299 name,
300 )),
301 )
302 }
303
parse_functional_pseudo_element<'t>( &self, name: CowRcStr<'i>, arguments: &mut CssParser<'i, 't>, ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>>304 fn parse_functional_pseudo_element<'t>(
305 &self,
306 name: CowRcStr<'i>,
307 arguments: &mut CssParser<'i, 't>,
308 ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
309 Err(
310 arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
311 name,
312 )),
313 )
314 }
315
default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl>316 fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
317 None
318 }
319
namespace_for_prefix( &self, _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix, ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl>320 fn namespace_for_prefix(
321 &self,
322 _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix,
323 ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
324 None
325 }
326 }
327
328 #[derive(Clone, Debug, Eq, PartialEq, ToShmem)]
329 #[shmem(no_bounds)]
330 pub struct SelectorList<Impl: SelectorImpl>(
331 #[shmem(field_bound)] pub SmallVec<[Selector<Impl>; 1]>,
332 );
333
334 /// How to treat invalid selectors in a selector list.
335 enum ParseErrorRecovery {
336 /// Discard the entire selector list, this is the default behavior for
337 /// almost all of CSS.
338 DiscardList,
339 /// Ignore invalid selectors, potentially creating an empty selector list.
340 ///
341 /// This is the error recovery mode of :is() and :where()
342 IgnoreInvalidSelector,
343 }
344
345 impl<Impl: SelectorImpl> SelectorList<Impl> {
346 /// Parse a comma-separated list of Selectors.
347 /// <https://drafts.csswg.org/selectors/#grouping>
348 ///
349 /// Return the Selectors or Err if there is an invalid selector.
parse<'i, 't, P>( parser: &P, input: &mut CssParser<'i, 't>, ) -> Result<Self, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>,350 pub fn parse<'i, 't, P>(
351 parser: &P,
352 input: &mut CssParser<'i, 't>,
353 ) -> Result<Self, ParseError<'i, P::Error>>
354 where
355 P: Parser<'i, Impl = Impl>,
356 {
357 Self::parse_with_state(
358 parser,
359 input,
360 SelectorParsingState::empty(),
361 ParseErrorRecovery::DiscardList,
362 )
363 }
364
365 #[inline]
parse_with_state<'i, 't, P>( parser: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, recovery: ParseErrorRecovery, ) -> Result<Self, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>,366 fn parse_with_state<'i, 't, P>(
367 parser: &P,
368 input: &mut CssParser<'i, 't>,
369 state: SelectorParsingState,
370 recovery: ParseErrorRecovery,
371 ) -> Result<Self, ParseError<'i, P::Error>>
372 where
373 P: Parser<'i, Impl = Impl>,
374 {
375 let mut values = SmallVec::new();
376 loop {
377 let selector = input.parse_until_before(Delimiter::Comma, |input| {
378 parse_selector(parser, input, state)
379 });
380
381 let was_ok = selector.is_ok();
382 match selector {
383 Ok(selector) => values.push(selector),
384 Err(err) => match recovery {
385 ParseErrorRecovery::DiscardList => return Err(err),
386 ParseErrorRecovery::IgnoreInvalidSelector => {},
387 },
388 }
389
390 loop {
391 match input.next() {
392 Err(_) => return Ok(SelectorList(values)),
393 Ok(&Token::Comma) => break,
394 Ok(_) => {
395 debug_assert!(!was_ok, "Shouldn't have got a selector if getting here");
396 },
397 }
398 }
399 }
400 }
401
402 /// Creates a SelectorList from a Vec of selectors. Used in tests.
from_vec(v: Vec<Selector<Impl>>) -> Self403 pub fn from_vec(v: Vec<Selector<Impl>>) -> Self {
404 SelectorList(SmallVec::from_vec(v))
405 }
406 }
407
408 /// Parses one compound selector suitable for nested stuff like :-moz-any, etc.
parse_inner_compound_selector<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, ) -> Result<Selector<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,409 fn parse_inner_compound_selector<'i, 't, P, Impl>(
410 parser: &P,
411 input: &mut CssParser<'i, 't>,
412 state: SelectorParsingState,
413 ) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
414 where
415 P: Parser<'i, Impl = Impl>,
416 Impl: SelectorImpl,
417 {
418 parse_selector(
419 parser,
420 input,
421 state | SelectorParsingState::DISALLOW_PSEUDOS | SelectorParsingState::DISALLOW_COMBINATORS,
422 )
423 }
424
425 /// Ancestor hashes for the bloom filter. We precompute these and store them
426 /// inline with selectors to optimize cache performance during matching.
427 /// This matters a lot.
428 ///
429 /// We use 4 hashes, which is copied from Gecko, who copied it from WebKit.
430 /// Note that increasing the number of hashes here will adversely affect the
431 /// cache hit when fast-rejecting long lists of Rules with inline hashes.
432 ///
433 /// Because the bloom filter only uses the bottom 24 bits of the hash, we pack
434 /// the fourth hash into the upper bits of the first three hashes in order to
435 /// shrink Rule (whose size matters a lot). This scheme minimizes the runtime
436 /// overhead of the packing for the first three hashes (we just need to mask
437 /// off the upper bits) at the expense of making the fourth somewhat more
438 /// complicated to assemble, because we often bail out before checking all the
439 /// hashes.
440 #[derive(Clone, Debug, Eq, PartialEq)]
441 pub struct AncestorHashes {
442 pub packed_hashes: [u32; 3],
443 }
444
collect_ancestor_hashes<Impl: SelectorImpl>( iter: SelectorIter<Impl>, quirks_mode: QuirksMode, hashes: &mut [u32; 4], len: &mut usize, ) -> bool where Impl::Identifier: PrecomputedHash, Impl::LocalName: PrecomputedHash, Impl::NamespaceUrl: PrecomputedHash,445 fn collect_ancestor_hashes<Impl: SelectorImpl>(
446 iter: SelectorIter<Impl>,
447 quirks_mode: QuirksMode,
448 hashes: &mut [u32; 4],
449 len: &mut usize,
450 ) -> bool
451 where
452 Impl::Identifier: PrecomputedHash,
453 Impl::LocalName: PrecomputedHash,
454 Impl::NamespaceUrl: PrecomputedHash,
455 {
456 for component in AncestorIter::new(iter) {
457 let hash = match *component {
458 Component::LocalName(LocalName {
459 ref name,
460 ref lower_name,
461 }) => {
462 // Only insert the local-name into the filter if it's all
463 // lowercase. Otherwise we would need to test both hashes, and
464 // our data structures aren't really set up for that.
465 if name != lower_name {
466 continue;
467 }
468 name.precomputed_hash()
469 },
470 Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => {
471 url.precomputed_hash()
472 },
473 // In quirks mode, class and id selectors should match
474 // case-insensitively, so just avoid inserting them into the filter.
475 Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => id.precomputed_hash(),
476 Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
477 class.precomputed_hash()
478 },
479 Component::AttributeInNoNamespace { ref local_name, .. } if Impl::should_collect_attr_hash(local_name) => {
480 // AttributeInNoNamespace is only used when local_name ==
481 // local_name_lower.
482 local_name.precomputed_hash()
483 },
484 Component::AttributeInNoNamespaceExists { ref local_name, ref local_name_lower, .. } => {
485 // Only insert the local-name into the filter if it's all
486 // lowercase. Otherwise we would need to test both hashes, and
487 // our data structures aren't really set up for that.
488 if local_name != local_name_lower || !Impl::should_collect_attr_hash(local_name) {
489 continue;
490 }
491 local_name.precomputed_hash()
492 },
493 Component::AttributeOther(ref selector) => {
494 if selector.local_name != selector.local_name_lower || !Impl::should_collect_attr_hash(&selector.local_name) {
495 continue;
496 }
497 selector.local_name.precomputed_hash()
498 },
499 Component::Is(ref list) | Component::Where(ref list) => {
500 // :where and :is OR their selectors, so we can't put any hash
501 // in the filter if there's more than one selector, as that'd
502 // exclude elements that may match one of the other selectors.
503 if list.len() == 1 &&
504 !collect_ancestor_hashes(list[0].iter(), quirks_mode, hashes, len)
505 {
506 return false;
507 }
508 continue;
509 },
510 _ => continue,
511 };
512
513 hashes[*len] = hash & BLOOM_HASH_MASK;
514 *len += 1;
515 if *len == hashes.len() {
516 return false;
517 }
518 }
519 true
520 }
521
522 impl AncestorHashes {
new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self where Impl::Identifier: PrecomputedHash, Impl::LocalName: PrecomputedHash, Impl::NamespaceUrl: PrecomputedHash,523 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self
524 where
525 Impl::Identifier: PrecomputedHash,
526 Impl::LocalName: PrecomputedHash,
527 Impl::NamespaceUrl: PrecomputedHash,
528 {
529 // Compute ancestor hashes for the bloom filter.
530 let mut hashes = [0u32; 4];
531 let mut len = 0;
532 collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len);
533 debug_assert!(len <= 4);
534
535 // Now, pack the fourth hash (if it exists) into the upper byte of each of
536 // the other three hashes.
537 if len == 4 {
538 let fourth = hashes[3];
539 hashes[0] |= (fourth & 0x000000ff) << 24;
540 hashes[1] |= (fourth & 0x0000ff00) << 16;
541 hashes[2] |= (fourth & 0x00ff0000) << 8;
542 }
543
544 AncestorHashes {
545 packed_hashes: [hashes[0], hashes[1], hashes[2]],
546 }
547 }
548
549 /// Returns the fourth hash, reassembled from parts.
fourth_hash(&self) -> u32550 pub fn fourth_hash(&self) -> u32 {
551 ((self.packed_hashes[0] & 0xff000000) >> 24) |
552 ((self.packed_hashes[1] & 0xff000000) >> 16) |
553 ((self.packed_hashes[2] & 0xff000000) >> 8)
554 }
555 }
556
namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl557 pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
558 // Rust type’s default, not default namespace
559 Impl::NamespaceUrl::default()
560 }
561
562 /// A Selector stores a sequence of simple selectors and combinators. The
563 /// iterator classes allow callers to iterate at either the raw sequence level or
564 /// at the level of sequences of simple selectors separated by combinators. Most
565 /// callers want the higher-level iterator.
566 ///
567 /// We store compound selectors internally right-to-left (in matching order).
568 /// Additionally, we invert the order of top-level compound selectors so that
569 /// each one matches left-to-right. This is because matching namespace, local name,
570 /// id, and class are all relatively cheap, whereas matching pseudo-classes might
571 /// be expensive (depending on the pseudo-class). Since authors tend to put the
572 /// pseudo-classes on the right, it's faster to start matching on the left.
573 ///
574 /// This reordering doesn't change the semantics of selector matching, and we
575 /// handle it in to_css to make it invisible to serialization.
576 #[derive(Clone, Eq, PartialEq, ToShmem)]
577 #[shmem(no_bounds)]
578 pub struct Selector<Impl: SelectorImpl>(
579 #[shmem(field_bound)] ThinArc<SpecificityAndFlags, Component<Impl>>,
580 );
581
582 impl<Impl: SelectorImpl> Selector<Impl> {
583 #[inline]
specificity(&self) -> u32584 pub fn specificity(&self) -> u32 {
585 self.0.header.header.specificity()
586 }
587
588 #[inline]
has_pseudo_element(&self) -> bool589 pub fn has_pseudo_element(&self) -> bool {
590 self.0.header.header.has_pseudo_element()
591 }
592
593 #[inline]
is_slotted(&self) -> bool594 pub fn is_slotted(&self) -> bool {
595 self.0.header.header.is_slotted()
596 }
597
598 #[inline]
is_part(&self) -> bool599 pub fn is_part(&self) -> bool {
600 self.0.header.header.is_part()
601 }
602
603 #[inline]
parts(&self) -> Option<&[Impl::Identifier]>604 pub fn parts(&self) -> Option<&[Impl::Identifier]> {
605 if !self.is_part() {
606 return None;
607 }
608
609 let mut iter = self.iter();
610 if self.has_pseudo_element() {
611 // Skip the pseudo-element.
612 for _ in &mut iter {}
613
614 let combinator = iter.next_sequence()?;
615 debug_assert_eq!(combinator, Combinator::PseudoElement);
616 }
617
618 for component in iter {
619 if let Component::Part(ref part) = *component {
620 return Some(part);
621 }
622 }
623
624 debug_assert!(false, "is_part() lied somehow?");
625 None
626 }
627
628 #[inline]
pseudo_element(&self) -> Option<&Impl::PseudoElement>629 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
630 if !self.has_pseudo_element() {
631 return None;
632 }
633
634 for component in self.iter() {
635 if let Component::PseudoElement(ref pseudo) = *component {
636 return Some(pseudo);
637 }
638 }
639
640 debug_assert!(false, "has_pseudo_element lied!");
641 None
642 }
643
644 /// Whether this selector (pseudo-element part excluded) matches every element.
645 ///
646 /// Used for "pre-computed" pseudo-elements in components/style/stylist.rs
647 #[inline]
is_universal(&self) -> bool648 pub fn is_universal(&self) -> bool {
649 self.iter_raw_match_order().all(|c| {
650 matches!(
651 *c,
652 Component::ExplicitUniversalType |
653 Component::ExplicitAnyNamespace |
654 Component::Combinator(Combinator::PseudoElement) |
655 Component::PseudoElement(..)
656 )
657 })
658 }
659
660 /// Returns an iterator over this selector in matching order (right-to-left).
661 /// When a combinator is reached, the iterator will return None, and
662 /// next_sequence() may be called to continue to the next sequence.
663 #[inline]
iter(&self) -> SelectorIter<Impl>664 pub fn iter(&self) -> SelectorIter<Impl> {
665 SelectorIter {
666 iter: self.iter_raw_match_order(),
667 next_combinator: None,
668 }
669 }
670
671 /// Whether this selector is a featureless :host selector, with no
672 /// combinators to the left, and optionally has a pseudo-element to the
673 /// right.
674 #[inline]
is_featureless_host_selector_or_pseudo_element(&self) -> bool675 pub fn is_featureless_host_selector_or_pseudo_element(&self) -> bool {
676 let mut iter = self.iter();
677 if !self.has_pseudo_element() {
678 return iter.is_featureless_host_selector();
679 }
680
681 // Skip the pseudo-element.
682 for _ in &mut iter {}
683
684 match iter.next_sequence() {
685 None => return false,
686 Some(combinator) => {
687 debug_assert_eq!(combinator, Combinator::PseudoElement);
688 },
689 }
690
691 iter.is_featureless_host_selector()
692 }
693
694 /// Returns an iterator over this selector in matching order (right-to-left),
695 /// skipping the rightmost |offset| Components.
696 #[inline]
iter_from(&self, offset: usize) -> SelectorIter<Impl>697 pub fn iter_from(&self, offset: usize) -> SelectorIter<Impl> {
698 let iter = self.0.slice[offset..].iter();
699 SelectorIter {
700 iter,
701 next_combinator: None,
702 }
703 }
704
705 /// Returns the combinator at index `index` (zero-indexed from the right),
706 /// or panics if the component is not a combinator.
707 #[inline]
combinator_at_match_order(&self, index: usize) -> Combinator708 pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
709 match self.0.slice[index] {
710 Component::Combinator(c) => c,
711 ref other => panic!(
712 "Not a combinator: {:?}, {:?}, index: {}",
713 other, self, index
714 ),
715 }
716 }
717
718 /// Returns an iterator over the entire sequence of simple selectors and
719 /// combinators, in matching order (from right to left).
720 #[inline]
iter_raw_match_order(&self) -> slice::Iter<Component<Impl>>721 pub fn iter_raw_match_order(&self) -> slice::Iter<Component<Impl>> {
722 self.0.slice.iter()
723 }
724
725 /// Returns the combinator at index `index` (zero-indexed from the left),
726 /// or panics if the component is not a combinator.
727 #[inline]
combinator_at_parse_order(&self, index: usize) -> Combinator728 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
729 match self.0.slice[self.len() - index - 1] {
730 Component::Combinator(c) => c,
731 ref other => panic!(
732 "Not a combinator: {:?}, {:?}, index: {}",
733 other, self, index
734 ),
735 }
736 }
737
738 /// Returns an iterator over the sequence of simple selectors and
739 /// combinators, in parse order (from left to right), starting from
740 /// `offset`.
741 #[inline]
iter_raw_parse_order_from(&self, offset: usize) -> Rev<slice::Iter<Component<Impl>>>742 pub fn iter_raw_parse_order_from(&self, offset: usize) -> Rev<slice::Iter<Component<Impl>>> {
743 self.0.slice[..self.len() - offset].iter().rev()
744 }
745
746 /// Creates a Selector from a vec of Components, specified in parse order. Used in tests.
747 #[allow(unused)]
from_vec( vec: Vec<Component<Impl>>, specificity: u32, flags: SelectorFlags, ) -> Self748 pub(crate) fn from_vec(
749 vec: Vec<Component<Impl>>,
750 specificity: u32,
751 flags: SelectorFlags,
752 ) -> Self {
753 let mut builder = SelectorBuilder::default();
754 for component in vec.into_iter() {
755 if let Some(combinator) = component.as_combinator() {
756 builder.push_combinator(combinator);
757 } else {
758 builder.push_simple_selector(component);
759 }
760 }
761 let spec = SpecificityAndFlags { specificity, flags };
762 Selector(builder.build_with_specificity_and_flags(spec))
763 }
764
765 /// Returns count of simple selectors and combinators in the Selector.
766 #[inline]
len(&self) -> usize767 pub fn len(&self) -> usize {
768 self.0.slice.len()
769 }
770
771 /// Returns the address on the heap of the ThinArc for memory reporting.
thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void772 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
773 self.0.heap_ptr()
774 }
775
776 /// Traverse selector components inside `self`.
777 ///
778 /// Implementations of this method should call `SelectorVisitor` methods
779 /// or other impls of `Visit` as appropriate based on the fields of `Self`.
780 ///
781 /// A return value of `false` indicates terminating the traversal.
782 /// It should be propagated with an early return.
783 /// On the contrary, `true` indicates that all fields of `self` have been traversed:
784 ///
785 /// ```rust,ignore
786 /// if !visitor.visit_simple_selector(&self.some_simple_selector) {
787 /// return false;
788 /// }
789 /// if !self.some_component.visit(visitor) {
790 /// return false;
791 /// }
792 /// true
793 /// ```
visit<V>(&self, visitor: &mut V) -> bool where V: SelectorVisitor<Impl = Impl>,794 pub fn visit<V>(&self, visitor: &mut V) -> bool
795 where
796 V: SelectorVisitor<Impl = Impl>,
797 {
798 let mut current = self.iter();
799 let mut combinator = None;
800 loop {
801 if !visitor.visit_complex_selector(combinator) {
802 return false;
803 }
804
805 for selector in &mut current {
806 if !selector.visit(visitor) {
807 return false;
808 }
809 }
810
811 combinator = current.next_sequence();
812 if combinator.is_none() {
813 break;
814 }
815 }
816
817 true
818 }
819 }
820
821 #[derive(Clone)]
822 pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
823 iter: slice::Iter<'a, Component<Impl>>,
824 next_combinator: Option<Combinator>,
825 }
826
827 impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
828 /// Prepares this iterator to point to the next sequence to the left,
829 /// returning the combinator if the sequence was found.
830 #[inline]
next_sequence(&mut self) -> Option<Combinator>831 pub fn next_sequence(&mut self) -> Option<Combinator> {
832 self.next_combinator.take()
833 }
834
835 /// Whether this selector is a featureless host selector, with no
836 /// combinators to the left.
837 #[inline]
is_featureless_host_selector(&mut self) -> bool838 pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
839 self.selector_length() > 0 &&
840 self.all(|component| component.is_host()) &&
841 self.next_sequence().is_none()
842 }
843
844 #[inline]
matches_for_stateless_pseudo_element(&mut self) -> bool845 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
846 let first = match self.next() {
847 Some(c) => c,
848 // Note that this is the common path that we keep inline: the
849 // pseudo-element not having anything to its right.
850 None => return true,
851 };
852 self.matches_for_stateless_pseudo_element_internal(first)
853 }
854
855 #[inline(never)]
matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool856 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool {
857 if !first.matches_for_stateless_pseudo_element() {
858 return false;
859 }
860 for component in self {
861 // The only other parser-allowed Components in this sequence are
862 // state pseudo-classes, or one of the other things that can contain
863 // them.
864 if !component.matches_for_stateless_pseudo_element() {
865 return false;
866 }
867 }
868 true
869 }
870
871 /// Returns remaining count of the simple selectors and combinators in the Selector.
872 #[inline]
selector_length(&self) -> usize873 pub fn selector_length(&self) -> usize {
874 self.iter.len()
875 }
876 }
877
878 impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
879 type Item = &'a Component<Impl>;
880
881 #[inline]
next(&mut self) -> Option<Self::Item>882 fn next(&mut self) -> Option<Self::Item> {
883 debug_assert!(
884 self.next_combinator.is_none(),
885 "You should call next_sequence!"
886 );
887 match *self.iter.next()? {
888 Component::Combinator(c) => {
889 self.next_combinator = Some(c);
890 None
891 },
892 ref x => Some(x),
893 }
894 }
895 }
896
897 impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result898 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
899 let iter = self.iter.clone().rev();
900 for component in iter {
901 component.to_css(f)?
902 }
903 Ok(())
904 }
905 }
906
907 /// An iterator over all simple selectors belonging to ancestors.
908 struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
909 impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
910 /// Creates an AncestorIter. The passed-in iterator is assumed to point to
911 /// the beginning of the child sequence, which will be skipped.
new(inner: SelectorIter<'a, Impl>) -> Self912 fn new(inner: SelectorIter<'a, Impl>) -> Self {
913 let mut result = AncestorIter(inner);
914 result.skip_until_ancestor();
915 result
916 }
917
918 /// Skips a sequence of simple selectors and all subsequent sequences until
919 /// a non-pseudo-element ancestor combinator is reached.
skip_until_ancestor(&mut self)920 fn skip_until_ancestor(&mut self) {
921 loop {
922 while self.0.next().is_some() {}
923 // If this is ever changed to stop at the "pseudo-element"
924 // combinator, we will need to fix the way we compute hashes for
925 // revalidation selectors.
926 if self.0.next_sequence().map_or(true, |x| {
927 matches!(x, Combinator::Child | Combinator::Descendant)
928 }) {
929 break;
930 }
931 }
932 }
933 }
934
935 impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
936 type Item = &'a Component<Impl>;
next(&mut self) -> Option<Self::Item>937 fn next(&mut self) -> Option<Self::Item> {
938 // Grab the next simple selector in the sequence if available.
939 let next = self.0.next();
940 if next.is_some() {
941 return next;
942 }
943
944 // See if there are more sequences. If so, skip any non-ancestor sequences.
945 if let Some(combinator) = self.0.next_sequence() {
946 if !matches!(combinator, Combinator::Child | Combinator::Descendant) {
947 self.skip_until_ancestor();
948 }
949 }
950
951 self.0.next()
952 }
953 }
954
955 #[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
956 pub enum Combinator {
957 Child, // >
958 Descendant, // space
959 NextSibling, // +
960 LaterSibling, // ~
961 /// A dummy combinator we use to the left of pseudo-elements.
962 ///
963 /// It serializes as the empty string, and acts effectively as a child
964 /// combinator in most cases. If we ever actually start using a child
965 /// combinator for this, we will need to fix up the way hashes are computed
966 /// for revalidation selectors.
967 PseudoElement,
968 /// Another combinator used for ::slotted(), which represent the jump from
969 /// a node to its assigned slot.
970 SlotAssignment,
971 /// Another combinator used for `::part()`, which represents the jump from
972 /// the part to the containing shadow host.
973 Part,
974 }
975
976 impl Combinator {
977 /// Returns true if this combinator is a child or descendant combinator.
978 #[inline]
is_ancestor(&self) -> bool979 pub fn is_ancestor(&self) -> bool {
980 matches!(
981 *self,
982 Combinator::Child |
983 Combinator::Descendant |
984 Combinator::PseudoElement |
985 Combinator::SlotAssignment
986 )
987 }
988
989 /// Returns true if this combinator is a pseudo-element combinator.
990 #[inline]
is_pseudo_element(&self) -> bool991 pub fn is_pseudo_element(&self) -> bool {
992 matches!(*self, Combinator::PseudoElement)
993 }
994
995 /// Returns true if this combinator is a next- or later-sibling combinator.
996 #[inline]
is_sibling(&self) -> bool997 pub fn is_sibling(&self) -> bool {
998 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
999 }
1000 }
1001
1002 /// A CSS simple selector or combinator. We store both in the same enum for
1003 /// optimal packing and cache performance, see [1].
1004 ///
1005 /// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1357973
1006 #[derive(Clone, Eq, PartialEq, ToShmem)]
1007 #[shmem(no_bounds)]
1008 pub enum Component<Impl: SelectorImpl> {
1009 Combinator(Combinator),
1010
1011 ExplicitAnyNamespace,
1012 ExplicitNoNamespace,
1013 DefaultNamespace(#[shmem(field_bound)] Impl::NamespaceUrl),
1014 Namespace(
1015 #[shmem(field_bound)] Impl::NamespacePrefix,
1016 #[shmem(field_bound)] Impl::NamespaceUrl,
1017 ),
1018
1019 ExplicitUniversalType,
1020 LocalName(LocalName<Impl>),
1021
1022 ID(#[shmem(field_bound)] Impl::Identifier),
1023 Class(#[shmem(field_bound)] Impl::Identifier),
1024
1025 AttributeInNoNamespaceExists {
1026 #[shmem(field_bound)]
1027 local_name: Impl::LocalName,
1028 local_name_lower: Impl::LocalName,
1029 },
1030 // Used only when local_name is already lowercase.
1031 AttributeInNoNamespace {
1032 local_name: Impl::LocalName,
1033 operator: AttrSelectorOperator,
1034 #[shmem(field_bound)]
1035 value: Impl::AttrValue,
1036 case_sensitivity: ParsedCaseSensitivity,
1037 never_matches: bool,
1038 },
1039 // Use a Box in the less common cases with more data to keep size_of::<Component>() small.
1040 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
1041
1042 /// Pseudo-classes
1043 Negation(Box<[Selector<Impl>]>),
1044 FirstChild,
1045 LastChild,
1046 OnlyChild,
1047 Root,
1048 Empty,
1049 Scope,
1050 NthChild(i32, i32),
1051 NthLastChild(i32, i32),
1052 NthOfType(i32, i32),
1053 NthLastOfType(i32, i32),
1054 FirstOfType,
1055 LastOfType,
1056 OnlyOfType,
1057 NonTSPseudoClass(#[shmem(field_bound)] Impl::NonTSPseudoClass),
1058 /// The ::slotted() pseudo-element:
1059 ///
1060 /// https://drafts.csswg.org/css-scoping/#slotted-pseudo
1061 ///
1062 /// The selector here is a compound selector, that is, no combinators.
1063 ///
1064 /// NOTE(emilio): This should support a list of selectors, but as of this
1065 /// writing no other browser does, and that allows them to put ::slotted()
1066 /// in the rule hash, so we do that too.
1067 ///
1068 /// See https://github.com/w3c/csswg-drafts/issues/2158
1069 Slotted(Selector<Impl>),
1070 /// The `::part` pseudo-element.
1071 /// https://drafts.csswg.org/css-shadow-parts/#part
1072 Part(#[shmem(field_bound)] Box<[Impl::Identifier]>),
1073 /// The `:host` pseudo-class:
1074 ///
1075 /// https://drafts.csswg.org/css-scoping/#host-selector
1076 ///
1077 /// NOTE(emilio): This should support a list of selectors, but as of this
1078 /// writing no other browser does, and that allows them to put :host()
1079 /// in the rule hash, so we do that too.
1080 ///
1081 /// See https://github.com/w3c/csswg-drafts/issues/2158
1082 Host(Option<Selector<Impl>>),
1083 /// The `:where` pseudo-class.
1084 ///
1085 /// https://drafts.csswg.org/selectors/#zero-matches
1086 ///
1087 /// The inner argument is conceptually a SelectorList, but we move the
1088 /// selectors to the heap to keep Component small.
1089 Where(Box<[Selector<Impl>]>),
1090 /// The `:is` pseudo-class.
1091 ///
1092 /// https://drafts.csswg.org/selectors/#matches-pseudo
1093 ///
1094 /// Same comment as above re. the argument.
1095 Is(Box<[Selector<Impl>]>),
1096 /// An implementation-dependent pseudo-element selector.
1097 PseudoElement(#[shmem(field_bound)] Impl::PseudoElement),
1098 }
1099
1100 impl<Impl: SelectorImpl> Component<Impl> {
1101 /// Returns true if this is a combinator.
1102 #[inline]
is_combinator(&self) -> bool1103 pub fn is_combinator(&self) -> bool {
1104 matches!(*self, Component::Combinator(_))
1105 }
1106
1107 /// Returns true if this is a :host() selector.
1108 #[inline]
is_host(&self) -> bool1109 pub fn is_host(&self) -> bool {
1110 matches!(*self, Component::Host(..))
1111 }
1112
1113 /// Returns the value as a combinator if applicable, None otherwise.
as_combinator(&self) -> Option<Combinator>1114 pub fn as_combinator(&self) -> Option<Combinator> {
1115 match *self {
1116 Component::Combinator(c) => Some(c),
1117 _ => None,
1118 }
1119 }
1120
1121 /// Whether this component is valid after a pseudo-element. Only intended
1122 /// for sanity-checking.
maybe_allowed_after_pseudo_element(&self) -> bool1123 pub fn maybe_allowed_after_pseudo_element(&self) -> bool {
1124 match *self {
1125 Component::NonTSPseudoClass(..) => true,
1126 Component::Negation(ref selectors) |
1127 Component::Is(ref selectors) |
1128 Component::Where(ref selectors) => selectors.iter().all(|selector| {
1129 selector
1130 .iter_raw_match_order()
1131 .all(|c| c.maybe_allowed_after_pseudo_element())
1132 }),
1133 _ => false,
1134 }
1135 }
1136
1137 /// Whether a given selector should match for stateless pseudo-elements.
1138 ///
1139 /// This is a bit subtle: Only selectors that return true in
1140 /// `maybe_allowed_after_pseudo_element` should end up here, and
1141 /// `NonTSPseudoClass` never matches (as it is a stateless pseudo after
1142 /// all).
matches_for_stateless_pseudo_element(&self) -> bool1143 fn matches_for_stateless_pseudo_element(&self) -> bool {
1144 debug_assert!(
1145 self.maybe_allowed_after_pseudo_element(),
1146 "Someone messed up pseudo-element parsing: {:?}",
1147 *self
1148 );
1149 match *self {
1150 Component::Negation(ref selectors) => !selectors.iter().all(|selector| {
1151 selector
1152 .iter_raw_match_order()
1153 .all(|c| c.matches_for_stateless_pseudo_element())
1154 }),
1155 Component::Is(ref selectors) | Component::Where(ref selectors) => {
1156 selectors.iter().any(|selector| {
1157 selector
1158 .iter_raw_match_order()
1159 .all(|c| c.matches_for_stateless_pseudo_element())
1160 })
1161 },
1162 _ => false,
1163 }
1164 }
1165
visit<V>(&self, visitor: &mut V) -> bool where V: SelectorVisitor<Impl = Impl>,1166 pub fn visit<V>(&self, visitor: &mut V) -> bool
1167 where
1168 V: SelectorVisitor<Impl = Impl>,
1169 {
1170 use self::Component::*;
1171 if !visitor.visit_simple_selector(self) {
1172 return false;
1173 }
1174
1175 match *self {
1176 Slotted(ref selector) => {
1177 if !selector.visit(visitor) {
1178 return false;
1179 }
1180 },
1181 Host(Some(ref selector)) => {
1182 if !selector.visit(visitor) {
1183 return false;
1184 }
1185 },
1186 AttributeInNoNamespaceExists {
1187 ref local_name,
1188 ref local_name_lower,
1189 } => {
1190 if !visitor.visit_attribute_selector(
1191 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
1192 local_name,
1193 local_name_lower,
1194 ) {
1195 return false;
1196 }
1197 },
1198 AttributeInNoNamespace {
1199 ref local_name,
1200 never_matches,
1201 ..
1202 } if !never_matches => {
1203 if !visitor.visit_attribute_selector(
1204 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
1205 local_name,
1206 local_name,
1207 ) {
1208 return false;
1209 }
1210 },
1211 AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
1212 let empty_string;
1213 let namespace = match attr_selector.namespace() {
1214 Some(ns) => ns,
1215 None => {
1216 empty_string = crate::parser::namespace_empty_string::<Impl>();
1217 NamespaceConstraint::Specific(&empty_string)
1218 },
1219 };
1220 if !visitor.visit_attribute_selector(
1221 &namespace,
1222 &attr_selector.local_name,
1223 &attr_selector.local_name_lower,
1224 ) {
1225 return false;
1226 }
1227 },
1228
1229 NonTSPseudoClass(ref pseudo_class) => {
1230 if !pseudo_class.visit(visitor) {
1231 return false;
1232 }
1233 },
1234
1235 Negation(ref list) | Is(ref list) | Where(ref list) => {
1236 if !visitor.visit_selector_list(&list) {
1237 return false;
1238 }
1239 },
1240 _ => {},
1241 }
1242
1243 true
1244 }
1245 }
1246
1247 #[derive(Clone, Eq, PartialEq, ToShmem)]
1248 #[shmem(no_bounds)]
1249 pub struct LocalName<Impl: SelectorImpl> {
1250 #[shmem(field_bound)]
1251 pub name: Impl::LocalName,
1252 pub lower_name: Impl::LocalName,
1253 }
1254
1255 impl<Impl: SelectorImpl> Debug for Selector<Impl> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1256 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1257 f.write_str("Selector(")?;
1258 self.to_css(f)?;
1259 write!(f, ", specificity = 0x{:x})", self.specificity())
1260 }
1261 }
1262
1263 impl<Impl: SelectorImpl> Debug for Component<Impl> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1264 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1265 self.to_css(f)
1266 }
1267 }
1268 impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1269 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1270 self.to_css(f)
1271 }
1272 }
1273 impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1274 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1275 self.to_css(f)
1276 }
1277 }
1278
serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result where Impl: SelectorImpl, I: Iterator<Item = &'a Selector<Impl>>, W: fmt::Write,1279 fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
1280 where
1281 Impl: SelectorImpl,
1282 I: Iterator<Item = &'a Selector<Impl>>,
1283 W: fmt::Write,
1284 {
1285 let mut first = true;
1286 for selector in iter {
1287 if !first {
1288 dest.write_str(", ")?;
1289 }
1290 first = false;
1291 selector.to_css(dest)?;
1292 }
1293 Ok(())
1294 }
1295
1296 impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,1297 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1298 where
1299 W: fmt::Write,
1300 {
1301 serialize_selector_list(self.0.iter(), dest)
1302 }
1303 }
1304
1305 impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,1306 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1307 where
1308 W: fmt::Write,
1309 {
1310 // Compound selectors invert the order of their contents, so we need to
1311 // undo that during serialization.
1312 //
1313 // This two-iterator strategy involves walking over the selector twice.
1314 // We could do something more clever, but selector serialization probably
1315 // isn't hot enough to justify it, and the stringification likely
1316 // dominates anyway.
1317 //
1318 // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(),
1319 // which we need for |split|. So we split by combinators on a match-order
1320 // sequence and then reverse.
1321
1322 let mut combinators = self
1323 .iter_raw_match_order()
1324 .rev()
1325 .filter_map(|x| x.as_combinator());
1326 let compound_selectors = self
1327 .iter_raw_match_order()
1328 .as_slice()
1329 .split(|x| x.is_combinator())
1330 .rev();
1331
1332 let mut combinators_exhausted = false;
1333 for compound in compound_selectors {
1334 debug_assert!(!combinators_exhausted);
1335
1336 // https://drafts.csswg.org/cssom/#serializing-selectors
1337 if compound.is_empty() {
1338 continue;
1339 }
1340
1341 // 1. If there is only one simple selector in the compound selectors
1342 // which is a universal selector, append the result of
1343 // serializing the universal selector to s.
1344 //
1345 // Check if `!compound.empty()` first--this can happen if we have
1346 // something like `... > ::before`, because we store `>` and `::`
1347 // both as combinators internally.
1348 //
1349 // If we are in this case, after we have serialized the universal
1350 // selector, we skip Step 2 and continue with the algorithm.
1351 let (can_elide_namespace, first_non_namespace) = match compound[0] {
1352 Component::ExplicitAnyNamespace |
1353 Component::ExplicitNoNamespace |
1354 Component::Namespace(..) => (false, 1),
1355 Component::DefaultNamespace(..) => (true, 1),
1356 _ => (true, 0),
1357 };
1358 let mut perform_step_2 = true;
1359 let next_combinator = combinators.next();
1360 if first_non_namespace == compound.len() - 1 {
1361 match (next_combinator, &compound[first_non_namespace]) {
1362 // We have to be careful here, because if there is a
1363 // pseudo element "combinator" there isn't really just
1364 // the one simple selector. Technically this compound
1365 // selector contains the pseudo element selector as well
1366 // -- Combinator::PseudoElement, just like
1367 // Combinator::SlotAssignment, don't exist in the
1368 // spec.
1369 (Some(Combinator::PseudoElement), _) |
1370 (Some(Combinator::SlotAssignment), _) => (),
1371 (_, &Component::ExplicitUniversalType) => {
1372 // Iterate over everything so we serialize the namespace
1373 // too.
1374 for simple in compound.iter() {
1375 simple.to_css(dest)?;
1376 }
1377 // Skip step 2, which is an "otherwise".
1378 perform_step_2 = false;
1379 },
1380 _ => (),
1381 }
1382 }
1383
1384 // 2. Otherwise, for each simple selector in the compound selectors
1385 // that is not a universal selector of which the namespace prefix
1386 // maps to a namespace that is not the default namespace
1387 // serialize the simple selector and append the result to s.
1388 //
1389 // See https://github.com/w3c/csswg-drafts/issues/1606, which is
1390 // proposing to change this to match up with the behavior asserted
1391 // in cssom/serialize-namespaced-type-selectors.html, which the
1392 // following code tries to match.
1393 if perform_step_2 {
1394 for simple in compound.iter() {
1395 if let Component::ExplicitUniversalType = *simple {
1396 // Can't have a namespace followed by a pseudo-element
1397 // selector followed by a universal selector in the same
1398 // compound selector, so we don't have to worry about the
1399 // real namespace being in a different `compound`.
1400 if can_elide_namespace {
1401 continue;
1402 }
1403 }
1404 simple.to_css(dest)?;
1405 }
1406 }
1407
1408 // 3. If this is not the last part of the chain of the selector
1409 // append a single SPACE (U+0020), followed by the combinator
1410 // ">", "+", "~", ">>", "||", as appropriate, followed by another
1411 // single SPACE (U+0020) if the combinator was not whitespace, to
1412 // s.
1413 match next_combinator {
1414 Some(c) => c.to_css(dest)?,
1415 None => combinators_exhausted = true,
1416 };
1417
1418 // 4. If this is the last part of the chain of the selector and
1419 // there is a pseudo-element, append "::" followed by the name of
1420 // the pseudo-element, to s.
1421 //
1422 // (we handle this above)
1423 }
1424
1425 Ok(())
1426 }
1427 }
1428
1429 impl ToCss for Combinator {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,1430 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1431 where
1432 W: fmt::Write,
1433 {
1434 match *self {
1435 Combinator::Child => dest.write_str(" > "),
1436 Combinator::Descendant => dest.write_str(" "),
1437 Combinator::NextSibling => dest.write_str(" + "),
1438 Combinator::LaterSibling => dest.write_str(" ~ "),
1439 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => Ok(()),
1440 }
1441 }
1442 }
1443
1444 impl<Impl: SelectorImpl> ToCss for Component<Impl> {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,1445 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1446 where
1447 W: fmt::Write,
1448 {
1449 use self::Component::*;
1450
1451 /// Serialize <an+b> values (part of the CSS Syntax spec, but currently only used here).
1452 /// <https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value>
1453 fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result
1454 where
1455 W: fmt::Write,
1456 {
1457 match (a, b) {
1458 (0, 0) => dest.write_char('0'),
1459
1460 (1, 0) => dest.write_char('n'),
1461 (-1, 0) => dest.write_str("-n"),
1462 (_, 0) => write!(dest, "{}n", a),
1463
1464 (0, _) => write!(dest, "{}", b),
1465 (1, _) => write!(dest, "n{:+}", b),
1466 (-1, _) => write!(dest, "-n{:+}", b),
1467 (_, _) => write!(dest, "{}n{:+}", a, b),
1468 }
1469 }
1470
1471 match *self {
1472 Combinator(ref c) => c.to_css(dest),
1473 Slotted(ref selector) => {
1474 dest.write_str("::slotted(")?;
1475 selector.to_css(dest)?;
1476 dest.write_char(')')
1477 },
1478 Part(ref part_names) => {
1479 dest.write_str("::part(")?;
1480 for (i, name) in part_names.iter().enumerate() {
1481 if i != 0 {
1482 dest.write_char(' ')?;
1483 }
1484 name.to_css(dest)?;
1485 }
1486 dest.write_char(')')
1487 },
1488 PseudoElement(ref p) => p.to_css(dest),
1489 ID(ref s) => {
1490 dest.write_char('#')?;
1491 s.to_css(dest)
1492 },
1493 Class(ref s) => {
1494 dest.write_char('.')?;
1495 s.to_css(dest)
1496 },
1497 LocalName(ref s) => s.to_css(dest),
1498 ExplicitUniversalType => dest.write_char('*'),
1499
1500 DefaultNamespace(_) => Ok(()),
1501 ExplicitNoNamespace => dest.write_char('|'),
1502 ExplicitAnyNamespace => dest.write_str("*|"),
1503 Namespace(ref prefix, _) => {
1504 prefix.to_css(dest)?;
1505 dest.write_char('|')
1506 },
1507
1508 AttributeInNoNamespaceExists { ref local_name, .. } => {
1509 dest.write_char('[')?;
1510 local_name.to_css(dest)?;
1511 dest.write_char(']')
1512 },
1513 AttributeInNoNamespace {
1514 ref local_name,
1515 operator,
1516 ref value,
1517 case_sensitivity,
1518 ..
1519 } => {
1520 dest.write_char('[')?;
1521 local_name.to_css(dest)?;
1522 operator.to_css(dest)?;
1523 dest.write_char('"')?;
1524 value.to_css(dest)?;
1525 dest.write_char('"')?;
1526 match case_sensitivity {
1527 ParsedCaseSensitivity::CaseSensitive |
1528 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
1529 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1530 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1531 }
1532 dest.write_char(']')
1533 },
1534 AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
1535
1536 // Pseudo-classes
1537 FirstChild => dest.write_str(":first-child"),
1538 LastChild => dest.write_str(":last-child"),
1539 OnlyChild => dest.write_str(":only-child"),
1540 Root => dest.write_str(":root"),
1541 Empty => dest.write_str(":empty"),
1542 Scope => dest.write_str(":scope"),
1543 Host(ref selector) => {
1544 dest.write_str(":host")?;
1545 if let Some(ref selector) = *selector {
1546 dest.write_char('(')?;
1547 selector.to_css(dest)?;
1548 dest.write_char(')')?;
1549 }
1550 Ok(())
1551 },
1552 FirstOfType => dest.write_str(":first-of-type"),
1553 LastOfType => dest.write_str(":last-of-type"),
1554 OnlyOfType => dest.write_str(":only-of-type"),
1555 NthChild(a, b) | NthLastChild(a, b) | NthOfType(a, b) | NthLastOfType(a, b) => {
1556 match *self {
1557 NthChild(_, _) => dest.write_str(":nth-child(")?,
1558 NthLastChild(_, _) => dest.write_str(":nth-last-child(")?,
1559 NthOfType(_, _) => dest.write_str(":nth-of-type(")?,
1560 NthLastOfType(_, _) => dest.write_str(":nth-last-of-type(")?,
1561 _ => unreachable!(),
1562 }
1563 write_affine(dest, a, b)?;
1564 dest.write_char(')')
1565 },
1566 Is(ref list) | Where(ref list) | Negation(ref list) => {
1567 match *self {
1568 Where(..) => dest.write_str(":where(")?,
1569 Is(..) => dest.write_str(":is(")?,
1570 Negation(..) => dest.write_str(":not(")?,
1571 _ => unreachable!(),
1572 }
1573 serialize_selector_list(list.iter(), dest)?;
1574 dest.write_str(")")
1575 },
1576 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
1577 }
1578 }
1579 }
1580
1581 impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,1582 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1583 where
1584 W: fmt::Write,
1585 {
1586 dest.write_char('[')?;
1587 match self.namespace {
1588 Some(NamespaceConstraint::Specific((ref prefix, _))) => {
1589 prefix.to_css(dest)?;
1590 dest.write_char('|')?
1591 },
1592 Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
1593 None => {},
1594 }
1595 self.local_name.to_css(dest)?;
1596 match self.operation {
1597 ParsedAttrSelectorOperation::Exists => {},
1598 ParsedAttrSelectorOperation::WithValue {
1599 operator,
1600 case_sensitivity,
1601 ref expected_value,
1602 } => {
1603 operator.to_css(dest)?;
1604 dest.write_char('"')?;
1605 expected_value.to_css(dest)?;
1606 dest.write_char('"')?;
1607 match case_sensitivity {
1608 ParsedCaseSensitivity::CaseSensitive |
1609 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
1610 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1611 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1612 }
1613 },
1614 }
1615 dest.write_char(']')
1616 }
1617 }
1618
1619 impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,1620 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1621 where
1622 W: fmt::Write,
1623 {
1624 self.name.to_css(dest)
1625 }
1626 }
1627
1628 /// Build up a Selector.
1629 /// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
1630 ///
1631 /// `Err` means invalid selector.
parse_selector<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, mut state: SelectorParsingState, ) -> Result<Selector<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,1632 fn parse_selector<'i, 't, P, Impl>(
1633 parser: &P,
1634 input: &mut CssParser<'i, 't>,
1635 mut state: SelectorParsingState,
1636 ) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
1637 where
1638 P: Parser<'i, Impl = Impl>,
1639 Impl: SelectorImpl,
1640 {
1641 let mut builder = SelectorBuilder::default();
1642
1643 let mut has_pseudo_element = false;
1644 let mut slotted = false;
1645 let mut part = false;
1646 'outer_loop: loop {
1647 // Parse a sequence of simple selectors.
1648 let empty = parse_compound_selector(parser, &mut state, input, &mut builder)?;
1649 if empty {
1650 return Err(input.new_custom_error(if builder.has_combinators() {
1651 SelectorParseErrorKind::DanglingCombinator
1652 } else {
1653 SelectorParseErrorKind::EmptySelector
1654 }));
1655 }
1656
1657 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
1658 has_pseudo_element = state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
1659 slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
1660 part = state.intersects(SelectorParsingState::AFTER_PART);
1661 debug_assert!(has_pseudo_element || slotted || part);
1662 break;
1663 }
1664
1665 // Parse a combinator.
1666 let combinator;
1667 let mut any_whitespace = false;
1668 loop {
1669 let before_this_token = input.state();
1670 match input.next_including_whitespace() {
1671 Err(_e) => break 'outer_loop,
1672 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
1673 Ok(&Token::Delim('>')) => {
1674 combinator = Combinator::Child;
1675 break;
1676 },
1677 Ok(&Token::Delim('+')) => {
1678 combinator = Combinator::NextSibling;
1679 break;
1680 },
1681 Ok(&Token::Delim('~')) => {
1682 combinator = Combinator::LaterSibling;
1683 break;
1684 },
1685 Ok(_) => {
1686 input.reset(&before_this_token);
1687 if any_whitespace {
1688 combinator = Combinator::Descendant;
1689 break;
1690 } else {
1691 break 'outer_loop;
1692 }
1693 },
1694 }
1695 }
1696
1697 if !state.allows_combinators() {
1698 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
1699 }
1700
1701 builder.push_combinator(combinator);
1702 }
1703
1704 Ok(Selector(builder.build(has_pseudo_element, slotted, part)))
1705 }
1706
1707 impl<Impl: SelectorImpl> Selector<Impl> {
1708 /// Parse a selector, without any pseudo-element.
1709 #[inline]
parse<'i, 't, P>( parser: &P, input: &mut CssParser<'i, 't>, ) -> Result<Self, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>,1710 pub fn parse<'i, 't, P>(
1711 parser: &P,
1712 input: &mut CssParser<'i, 't>,
1713 ) -> Result<Self, ParseError<'i, P::Error>>
1714 where
1715 P: Parser<'i, Impl = Impl>,
1716 {
1717 parse_selector(parser, input, SelectorParsingState::empty())
1718 }
1719 }
1720
1721 /// * `Err(())`: Invalid selector, abort
1722 /// * `Ok(false)`: Not a type selector, could be something else. `input` was not consumed.
1723 /// * `Ok(true)`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
parse_type_selector<'i, 't, P, Impl, S>( parser: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, sink: &mut S, ) -> Result<bool, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl, S: Push<Component<Impl>>,1724 fn parse_type_selector<'i, 't, P, Impl, S>(
1725 parser: &P,
1726 input: &mut CssParser<'i, 't>,
1727 state: SelectorParsingState,
1728 sink: &mut S,
1729 ) -> Result<bool, ParseError<'i, P::Error>>
1730 where
1731 P: Parser<'i, Impl = Impl>,
1732 Impl: SelectorImpl,
1733 S: Push<Component<Impl>>,
1734 {
1735 match parse_qualified_name(parser, input, /* in_attr_selector = */ false) {
1736 Err(ParseError {
1737 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
1738 ..
1739 }) |
1740 Ok(OptionalQName::None(_)) => Ok(false),
1741 Ok(OptionalQName::Some(namespace, local_name)) => {
1742 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
1743 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
1744 }
1745 match namespace {
1746 QNamePrefix::ImplicitAnyNamespace => {},
1747 QNamePrefix::ImplicitDefaultNamespace(url) => {
1748 sink.push(Component::DefaultNamespace(url))
1749 },
1750 QNamePrefix::ExplicitNamespace(prefix, url) => {
1751 sink.push(match parser.default_namespace() {
1752 Some(ref default_url) if url == *default_url => {
1753 Component::DefaultNamespace(url)
1754 },
1755 _ => Component::Namespace(prefix, url),
1756 })
1757 },
1758 QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
1759 QNamePrefix::ExplicitAnyNamespace => {
1760 match parser.default_namespace() {
1761 // Element type selectors that have no namespace
1762 // component (no namespace separator) represent elements
1763 // without regard to the element's namespace (equivalent
1764 // to "*|") unless a default namespace has been declared
1765 // for namespaced selectors (e.g. in CSS, in the style
1766 // sheet). If a default namespace has been declared,
1767 // such selectors will represent only elements in the
1768 // default namespace.
1769 // -- Selectors § 6.1.1
1770 // So we'll have this act the same as the
1771 // QNamePrefix::ImplicitAnyNamespace case.
1772 None => {},
1773 Some(_) => sink.push(Component::ExplicitAnyNamespace),
1774 }
1775 },
1776 QNamePrefix::ImplicitNoNamespace => {
1777 unreachable!() // Not returned with in_attr_selector = false
1778 },
1779 }
1780 match local_name {
1781 Some(name) => sink.push(Component::LocalName(LocalName {
1782 lower_name: to_ascii_lowercase(&name).as_ref().into(),
1783 name: name.as_ref().into(),
1784 })),
1785 None => sink.push(Component::ExplicitUniversalType),
1786 }
1787 Ok(true)
1788 },
1789 Err(e) => Err(e),
1790 }
1791 }
1792
1793 #[derive(Debug)]
1794 enum SimpleSelectorParseResult<Impl: SelectorImpl> {
1795 SimpleSelector(Component<Impl>),
1796 PseudoElement(Impl::PseudoElement),
1797 SlottedPseudo(Selector<Impl>),
1798 PartPseudo(Box<[Impl::Identifier]>),
1799 }
1800
1801 #[derive(Debug)]
1802 enum QNamePrefix<Impl: SelectorImpl> {
1803 ImplicitNoNamespace, // `foo` in attr selectors
1804 ImplicitAnyNamespace, // `foo` in type selectors, without a default ns
1805 ImplicitDefaultNamespace(Impl::NamespaceUrl), // `foo` in type selectors, with a default ns
1806 ExplicitNoNamespace, // `|foo`
1807 ExplicitAnyNamespace, // `*|foo`
1808 ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo`
1809 }
1810
1811 enum OptionalQName<'i, Impl: SelectorImpl> {
1812 Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
1813 None(Token<'i>),
1814 }
1815
1816 /// * `Err(())`: Invalid selector, abort
1817 /// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed,
1818 /// but the token is still returned.
1819 /// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector
parse_qualified_name<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, in_attr_selector: bool, ) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,1820 fn parse_qualified_name<'i, 't, P, Impl>(
1821 parser: &P,
1822 input: &mut CssParser<'i, 't>,
1823 in_attr_selector: bool,
1824 ) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
1825 where
1826 P: Parser<'i, Impl = Impl>,
1827 Impl: SelectorImpl,
1828 {
1829 let default_namespace = |local_name| {
1830 let namespace = match parser.default_namespace() {
1831 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
1832 None => QNamePrefix::ImplicitAnyNamespace,
1833 };
1834 Ok(OptionalQName::Some(namespace, local_name))
1835 };
1836
1837 let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
1838 let location = input.current_source_location();
1839 match input.next_including_whitespace() {
1840 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
1841 Ok(&Token::Ident(ref local_name)) => {
1842 Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
1843 },
1844 Ok(t) if in_attr_selector => {
1845 let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
1846 Err(location.new_custom_error(e))
1847 },
1848 Ok(t) => Err(location.new_custom_error(
1849 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()),
1850 )),
1851 Err(e) => Err(e.into()),
1852 }
1853 };
1854
1855 let start = input.state();
1856 match input.next_including_whitespace() {
1857 Ok(Token::Ident(value)) => {
1858 let value = value.clone();
1859 let after_ident = input.state();
1860 match input.next_including_whitespace() {
1861 Ok(&Token::Delim('|')) => {
1862 let prefix = value.as_ref().into();
1863 let result = parser.namespace_for_prefix(&prefix);
1864 let url = result.ok_or(
1865 after_ident
1866 .source_location()
1867 .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
1868 )?;
1869 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
1870 },
1871 _ => {
1872 input.reset(&after_ident);
1873 if in_attr_selector {
1874 Ok(OptionalQName::Some(
1875 QNamePrefix::ImplicitNoNamespace,
1876 Some(value),
1877 ))
1878 } else {
1879 default_namespace(Some(value))
1880 }
1881 },
1882 }
1883 },
1884 Ok(Token::Delim('*')) => {
1885 let after_star = input.state();
1886 match input.next_including_whitespace() {
1887 Ok(&Token::Delim('|')) => {
1888 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
1889 },
1890 _ if !in_attr_selector => {
1891 input.reset(&after_star);
1892 default_namespace(None)
1893 }
1894 result => {
1895 let t = result?;
1896 Err(after_star
1897 .source_location()
1898 .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t.clone())))
1899 },
1900 }
1901 },
1902 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
1903 Ok(t) => {
1904 let t = t.clone();
1905 input.reset(&start);
1906 Ok(OptionalQName::None(t))
1907 },
1908 Err(e) => {
1909 input.reset(&start);
1910 Err(e.into())
1911 },
1912 }
1913 }
1914
parse_attribute_selector<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, ) -> Result<Component<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,1915 fn parse_attribute_selector<'i, 't, P, Impl>(
1916 parser: &P,
1917 input: &mut CssParser<'i, 't>,
1918 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
1919 where
1920 P: Parser<'i, Impl = Impl>,
1921 Impl: SelectorImpl,
1922 {
1923 let namespace;
1924 let local_name;
1925
1926 input.skip_whitespace();
1927
1928 match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
1929 OptionalQName::None(t) => {
1930 return Err(input.new_custom_error(
1931 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
1932 ));
1933 },
1934 OptionalQName::Some(_, None) => unreachable!(),
1935 OptionalQName::Some(ns, Some(ln)) => {
1936 local_name = ln;
1937 namespace = match ns {
1938 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
1939 QNamePrefix::ExplicitNamespace(prefix, url) => {
1940 Some(NamespaceConstraint::Specific((prefix, url)))
1941 },
1942 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
1943 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
1944 unreachable!() // Not returned with in_attr_selector = true
1945 },
1946 }
1947 },
1948 }
1949
1950 let location = input.current_source_location();
1951 let operator = match input.next() {
1952 // [foo]
1953 Err(_) => {
1954 let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
1955 let local_name = local_name.as_ref().into();
1956 if let Some(namespace) = namespace {
1957 return Ok(Component::AttributeOther(Box::new(
1958 AttrSelectorWithOptionalNamespace {
1959 namespace: Some(namespace),
1960 local_name,
1961 local_name_lower,
1962 operation: ParsedAttrSelectorOperation::Exists,
1963 never_matches: false,
1964 },
1965 )));
1966 } else {
1967 return Ok(Component::AttributeInNoNamespaceExists {
1968 local_name,
1969 local_name_lower,
1970 });
1971 }
1972 },
1973
1974 // [foo=bar]
1975 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
1976 // [foo~=bar]
1977 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
1978 // [foo|=bar]
1979 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
1980 // [foo^=bar]
1981 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
1982 // [foo*=bar]
1983 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
1984 // [foo$=bar]
1985 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
1986 Ok(t) => {
1987 return Err(location.new_custom_error(
1988 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()),
1989 ));
1990 },
1991 };
1992
1993 let value = match input.expect_ident_or_string() {
1994 Ok(t) => t.clone(),
1995 Err(BasicParseError {
1996 kind: BasicParseErrorKind::UnexpectedToken(t),
1997 location,
1998 }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
1999 Err(e) => return Err(e.into()),
2000 };
2001 let never_matches = match operator {
2002 AttrSelectorOperator::Equal | AttrSelectorOperator::DashMatch => false,
2003
2004 AttrSelectorOperator::Includes => value.is_empty() || value.contains(SELECTOR_WHITESPACE),
2005
2006 AttrSelectorOperator::Prefix |
2007 AttrSelectorOperator::Substring |
2008 AttrSelectorOperator::Suffix => value.is_empty(),
2009 };
2010
2011 let attribute_flags = parse_attribute_flags(input)?;
2012
2013 let value = value.as_ref().into();
2014 let local_name_lower;
2015 let local_name_is_ascii_lowercase;
2016 let case_sensitivity;
2017 {
2018 let local_name_lower_cow = to_ascii_lowercase(&local_name);
2019 case_sensitivity =
2020 attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
2021 local_name_lower = local_name_lower_cow.as_ref().into();
2022 local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
2023 }
2024 let local_name = local_name.as_ref().into();
2025 if namespace.is_some() || !local_name_is_ascii_lowercase {
2026 Ok(Component::AttributeOther(Box::new(
2027 AttrSelectorWithOptionalNamespace {
2028 namespace,
2029 local_name,
2030 local_name_lower,
2031 never_matches,
2032 operation: ParsedAttrSelectorOperation::WithValue {
2033 operator,
2034 case_sensitivity,
2035 expected_value: value,
2036 },
2037 },
2038 )))
2039 } else {
2040 Ok(Component::AttributeInNoNamespace {
2041 local_name,
2042 operator,
2043 value,
2044 case_sensitivity,
2045 never_matches,
2046 })
2047 }
2048 }
2049
2050 /// An attribute selector can have 's' or 'i' as flags, or no flags at all.
2051 enum AttributeFlags {
2052 // Matching should be case-sensitive ('s' flag).
2053 CaseSensitive,
2054 // Matching should be case-insensitive ('i' flag).
2055 AsciiCaseInsensitive,
2056 // No flags. Matching behavior depends on the name of the attribute.
2057 CaseSensitivityDependsOnName,
2058 }
2059
2060 impl AttributeFlags {
to_case_sensitivity(self, local_name: &str, have_namespace: bool) -> ParsedCaseSensitivity2061 fn to_case_sensitivity(self, local_name: &str, have_namespace: bool) -> ParsedCaseSensitivity {
2062 match self {
2063 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
2064 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
2065 AttributeFlags::CaseSensitivityDependsOnName => {
2066 if !have_namespace &&
2067 include!(concat!(
2068 env!("OUT_DIR"),
2069 "/ascii_case_insensitive_html_attributes.rs"
2070 ))
2071 .contains(local_name)
2072 {
2073 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
2074 } else {
2075 ParsedCaseSensitivity::CaseSensitive
2076 }
2077 },
2078 }
2079 }
2080 }
2081
parse_attribute_flags<'i, 't>( input: &mut CssParser<'i, 't>, ) -> Result<AttributeFlags, BasicParseError<'i>>2082 fn parse_attribute_flags<'i, 't>(
2083 input: &mut CssParser<'i, 't>,
2084 ) -> Result<AttributeFlags, BasicParseError<'i>> {
2085 let location = input.current_source_location();
2086 let token = match input.next() {
2087 Ok(t) => t,
2088 Err(..) => {
2089 // Selectors spec says language-defined; HTML says it depends on the
2090 // exact attribute name.
2091 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
2092 },
2093 };
2094
2095 let ident = match *token {
2096 Token::Ident(ref i) => i,
2097 ref other => return Err(location.new_basic_unexpected_token_error(other.clone())),
2098 };
2099
2100 Ok(match_ignore_ascii_case! {
2101 ident,
2102 "i" => AttributeFlags::AsciiCaseInsensitive,
2103 "s" => AttributeFlags::CaseSensitive,
2104 _ => return Err(location.new_basic_unexpected_token_error(token.clone())),
2105 })
2106 }
2107
2108 /// Level 3: Parse **one** simple_selector. (Though we might insert a second
2109 /// implied "<defaultns>|*" type selector.)
parse_negation<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, ) -> Result<Component<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,2110 fn parse_negation<'i, 't, P, Impl>(
2111 parser: &P,
2112 input: &mut CssParser<'i, 't>,
2113 state: SelectorParsingState,
2114 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2115 where
2116 P: Parser<'i, Impl = Impl>,
2117 Impl: SelectorImpl,
2118 {
2119 let list = SelectorList::parse_with_state(
2120 parser,
2121 input,
2122 state |
2123 SelectorParsingState::SKIP_DEFAULT_NAMESPACE |
2124 SelectorParsingState::DISALLOW_PSEUDOS,
2125 ParseErrorRecovery::DiscardList,
2126 )?;
2127
2128 Ok(Component::Negation(list.0.into_vec().into_boxed_slice()))
2129 }
2130
2131 /// simple_selector_sequence
2132 /// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
2133 /// | [ HASH | class | attrib | pseudo | negation ]+
2134 ///
2135 /// `Err(())` means invalid selector.
2136 /// `Ok(true)` is an empty selector
parse_compound_selector<'i, 't, P, Impl>( parser: &P, state: &mut SelectorParsingState, input: &mut CssParser<'i, 't>, builder: &mut SelectorBuilder<Impl>, ) -> Result<bool, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,2137 fn parse_compound_selector<'i, 't, P, Impl>(
2138 parser: &P,
2139 state: &mut SelectorParsingState,
2140 input: &mut CssParser<'i, 't>,
2141 builder: &mut SelectorBuilder<Impl>,
2142 ) -> Result<bool, ParseError<'i, P::Error>>
2143 where
2144 P: Parser<'i, Impl = Impl>,
2145 Impl: SelectorImpl,
2146 {
2147 input.skip_whitespace();
2148
2149 let mut empty = true;
2150 if parse_type_selector(parser, input, *state, builder)? {
2151 empty = false;
2152 }
2153
2154 loop {
2155 let result = match parse_one_simple_selector(parser, input, *state)? {
2156 None => break,
2157 Some(result) => result,
2158 };
2159
2160 if empty {
2161 if let Some(url) = parser.default_namespace() {
2162 // If there was no explicit type selector, but there is a
2163 // default namespace, there is an implicit "<defaultns>|*" type
2164 // selector. Except for :host() or :not() / :is() / :where(),
2165 // where we ignore it.
2166 //
2167 // https://drafts.csswg.org/css-scoping/#host-element-in-tree:
2168 //
2169 // When considered within its own shadow trees, the shadow
2170 // host is featureless. Only the :host, :host(), and
2171 // :host-context() pseudo-classes are allowed to match it.
2172 //
2173 // https://drafts.csswg.org/selectors-4/#featureless:
2174 //
2175 // A featureless element does not match any selector at all,
2176 // except those it is explicitly defined to match. If a
2177 // given selector is allowed to match a featureless element,
2178 // it must do so while ignoring the default namespace.
2179 //
2180 // https://drafts.csswg.org/selectors-4/#matches
2181 //
2182 // Default namespace declarations do not affect the compound
2183 // selector representing the subject of any selector within
2184 // a :is() pseudo-class, unless that compound selector
2185 // contains an explicit universal selector or type selector.
2186 //
2187 // (Similar quotes for :where() / :not())
2188 //
2189 let ignore_default_ns = state
2190 .intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE) ||
2191 matches!(
2192 result,
2193 SimpleSelectorParseResult::SimpleSelector(Component::Host(..))
2194 );
2195 if !ignore_default_ns {
2196 builder.push_simple_selector(Component::DefaultNamespace(url));
2197 }
2198 }
2199 }
2200
2201 empty = false;
2202
2203 match result {
2204 SimpleSelectorParseResult::SimpleSelector(s) => {
2205 builder.push_simple_selector(s);
2206 },
2207 SimpleSelectorParseResult::PartPseudo(part_names) => {
2208 state.insert(SelectorParsingState::AFTER_PART);
2209 builder.push_combinator(Combinator::Part);
2210 builder.push_simple_selector(Component::Part(part_names));
2211 },
2212 SimpleSelectorParseResult::SlottedPseudo(selector) => {
2213 state.insert(SelectorParsingState::AFTER_SLOTTED);
2214 builder.push_combinator(Combinator::SlotAssignment);
2215 builder.push_simple_selector(Component::Slotted(selector));
2216 },
2217 SimpleSelectorParseResult::PseudoElement(p) => {
2218 state.insert(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
2219 if !p.accepts_state_pseudo_classes() {
2220 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
2221 }
2222 builder.push_combinator(Combinator::PseudoElement);
2223 builder.push_simple_selector(Component::PseudoElement(p));
2224 },
2225 }
2226 }
2227 Ok(empty)
2228 }
2229
parse_is_or_where<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, component: impl FnOnce(Box<[Selector<Impl>]>) -> Component<Impl>, ) -> Result<Component<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,2230 fn parse_is_or_where<'i, 't, P, Impl>(
2231 parser: &P,
2232 input: &mut CssParser<'i, 't>,
2233 state: SelectorParsingState,
2234 component: impl FnOnce(Box<[Selector<Impl>]>) -> Component<Impl>,
2235 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2236 where
2237 P: Parser<'i, Impl = Impl>,
2238 Impl: SelectorImpl,
2239 {
2240 debug_assert!(parser.parse_is_and_where());
2241 // https://drafts.csswg.org/selectors/#matches-pseudo:
2242 //
2243 // Pseudo-elements cannot be represented by the matches-any
2244 // pseudo-class; they are not valid within :is().
2245 //
2246 let inner = SelectorList::parse_with_state(
2247 parser,
2248 input,
2249 state |
2250 SelectorParsingState::SKIP_DEFAULT_NAMESPACE |
2251 SelectorParsingState::DISALLOW_PSEUDOS,
2252 ParseErrorRecovery::IgnoreInvalidSelector,
2253 )?;
2254 Ok(component(inner.0.into_vec().into_boxed_slice()))
2255 }
2256
parse_functional_pseudo_class<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, name: CowRcStr<'i>, state: SelectorParsingState, ) -> Result<Component<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,2257 fn parse_functional_pseudo_class<'i, 't, P, Impl>(
2258 parser: &P,
2259 input: &mut CssParser<'i, 't>,
2260 name: CowRcStr<'i>,
2261 state: SelectorParsingState,
2262 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2263 where
2264 P: Parser<'i, Impl = Impl>,
2265 Impl: SelectorImpl,
2266 {
2267 match_ignore_ascii_case! { &name,
2268 "nth-child" => return parse_nth_pseudo_class(parser, input, state, Component::NthChild),
2269 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, Component::NthOfType),
2270 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, Component::NthLastChild),
2271 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, Component::NthLastOfType),
2272 "is" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Is),
2273 "where" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Where),
2274 "host" => {
2275 if !state.allows_tree_structural_pseudo_classes() {
2276 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2277 }
2278 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
2279 },
2280 "not" => {
2281 return parse_negation(parser, input, state)
2282 },
2283 _ => {}
2284 }
2285
2286 if parser.parse_is_and_where() && parser.is_is_alias(&name) {
2287 return parse_is_or_where(parser, input, state, Component::Is);
2288 }
2289
2290 if !state.allows_custom_functional_pseudo_classes() {
2291 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2292 }
2293
2294 P::parse_non_ts_functional_pseudo_class(parser, name, input).map(Component::NonTSPseudoClass)
2295 }
2296
parse_nth_pseudo_class<'i, 't, P, Impl, F>( _: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, selector: F, ) -> Result<Component<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component<Impl>,2297 fn parse_nth_pseudo_class<'i, 't, P, Impl, F>(
2298 _: &P,
2299 input: &mut CssParser<'i, 't>,
2300 state: SelectorParsingState,
2301 selector: F,
2302 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2303 where
2304 P: Parser<'i, Impl = Impl>,
2305 Impl: SelectorImpl,
2306 F: FnOnce(i32, i32) -> Component<Impl>,
2307 {
2308 if !state.allows_tree_structural_pseudo_classes() {
2309 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2310 }
2311 let (a, b) = parse_nth(input)?;
2312 Ok(selector(a, b))
2313 }
2314
2315 /// Returns whether the name corresponds to a CSS2 pseudo-element that
2316 /// can be specified with the single colon syntax (in addition to the
2317 /// double-colon syntax, which can be used for all pseudo-elements).
is_css2_pseudo_element(name: &str) -> bool2318 fn is_css2_pseudo_element(name: &str) -> bool {
2319 // ** Do not add to this list! **
2320 match_ignore_ascii_case! { name,
2321 "before" | "after" | "first-line" | "first-letter" => true,
2322 _ => false,
2323 }
2324 }
2325
2326 /// Parse a simple selector other than a type selector.
2327 ///
2328 /// * `Err(())`: Invalid selector, abort
2329 /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed.
2330 /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
parse_one_simple_selector<'i, 't, P, Impl>( parser: &P, input: &mut CssParser<'i, 't>, state: SelectorParsingState, ) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,2331 fn parse_one_simple_selector<'i, 't, P, Impl>(
2332 parser: &P,
2333 input: &mut CssParser<'i, 't>,
2334 state: SelectorParsingState,
2335 ) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
2336 where
2337 P: Parser<'i, Impl = Impl>,
2338 Impl: SelectorImpl,
2339 {
2340 let start = input.state();
2341 let token = match input.next_including_whitespace().map(|t| t.clone()) {
2342 Ok(t) => t,
2343 Err(..) => {
2344 input.reset(&start);
2345 return Ok(None);
2346 },
2347 };
2348
2349 Ok(Some(match token {
2350 Token::IDHash(id) => {
2351 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2352 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2353 }
2354 let id = Component::ID(id.as_ref().into());
2355 SimpleSelectorParseResult::SimpleSelector(id)
2356 },
2357 Token::Delim('.') => {
2358 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2359 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2360 }
2361 let location = input.current_source_location();
2362 let class = match *input.next_including_whitespace()? {
2363 Token::Ident(ref class) => class,
2364 ref t => {
2365 let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
2366 return Err(location.new_custom_error(e));
2367 },
2368 };
2369 let class = Component::Class(class.as_ref().into());
2370 SimpleSelectorParseResult::SimpleSelector(class)
2371 },
2372 Token::SquareBracketBlock => {
2373 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2374 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2375 }
2376 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
2377 SimpleSelectorParseResult::SimpleSelector(attr)
2378 },
2379 Token::Colon => {
2380 let location = input.current_source_location();
2381 let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
2382 Token::Colon => (false, input.next_including_whitespace()?.clone()),
2383 t => (true, t),
2384 };
2385 let (name, is_functional) = match next_token {
2386 Token::Ident(name) => (name, false),
2387 Token::Function(name) => (name, true),
2388 t => {
2389 let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t);
2390 return Err(input.new_custom_error(e));
2391 },
2392 };
2393 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
2394 if is_pseudo_element {
2395 if !state.allows_pseudos() {
2396 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2397 }
2398 let pseudo_element = if is_functional {
2399 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
2400 if !state.allows_part() {
2401 return Err(
2402 input.new_custom_error(SelectorParseErrorKind::InvalidState)
2403 );
2404 }
2405 let names = input.parse_nested_block(|input| {
2406 let mut result = Vec::with_capacity(1);
2407 result.push(input.expect_ident()?.as_ref().into());
2408 while !input.is_exhausted() {
2409 result.push(input.expect_ident()?.as_ref().into());
2410 }
2411 Ok(result.into_boxed_slice())
2412 })?;
2413 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
2414 }
2415 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
2416 if !state.allows_slotted() {
2417 return Err(
2418 input.new_custom_error(SelectorParseErrorKind::InvalidState)
2419 );
2420 }
2421 let selector = input.parse_nested_block(|input| {
2422 parse_inner_compound_selector(parser, input, state)
2423 })?;
2424 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
2425 }
2426 input.parse_nested_block(|input| {
2427 P::parse_functional_pseudo_element(parser, name, input)
2428 })?
2429 } else {
2430 P::parse_pseudo_element(parser, location, name)?
2431 };
2432
2433 if state.intersects(SelectorParsingState::AFTER_SLOTTED) &&
2434 !pseudo_element.valid_after_slotted()
2435 {
2436 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2437 }
2438 SimpleSelectorParseResult::PseudoElement(pseudo_element)
2439 } else {
2440 let pseudo_class = if is_functional {
2441 input.parse_nested_block(|input| {
2442 parse_functional_pseudo_class(parser, input, name, state)
2443 })?
2444 } else {
2445 parse_simple_pseudo_class(parser, location, name, state)?
2446 };
2447 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
2448 }
2449 },
2450 _ => {
2451 input.reset(&start);
2452 return Ok(None);
2453 },
2454 }))
2455 }
2456
parse_simple_pseudo_class<'i, P, Impl>( parser: &P, location: SourceLocation, name: CowRcStr<'i>, state: SelectorParsingState, ) -> Result<Component<Impl>, ParseError<'i, P::Error>> where P: Parser<'i, Impl = Impl>, Impl: SelectorImpl,2457 fn parse_simple_pseudo_class<'i, P, Impl>(
2458 parser: &P,
2459 location: SourceLocation,
2460 name: CowRcStr<'i>,
2461 state: SelectorParsingState,
2462 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2463 where
2464 P: Parser<'i, Impl = Impl>,
2465 Impl: SelectorImpl,
2466 {
2467 if !state.allows_non_functional_pseudo_classes() {
2468 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
2469 }
2470
2471 if state.allows_tree_structural_pseudo_classes() {
2472 match_ignore_ascii_case! { &name,
2473 "first-child" => return Ok(Component::FirstChild),
2474 "last-child" => return Ok(Component::LastChild),
2475 "only-child" => return Ok(Component::OnlyChild),
2476 "root" => return Ok(Component::Root),
2477 "empty" => return Ok(Component::Empty),
2478 "scope" => return Ok(Component::Scope),
2479 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
2480 "first-of-type" => return Ok(Component::FirstOfType),
2481 "last-of-type" => return Ok(Component::LastOfType),
2482 "only-of-type" => return Ok(Component::OnlyOfType),
2483 _ => {},
2484 }
2485 }
2486
2487 let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
2488 if state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT) &&
2489 !pseudo_class.is_user_action_state()
2490 {
2491 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
2492 }
2493 Ok(Component::NonTSPseudoClass(pseudo_class))
2494 }
2495
2496 // NB: pub module in order to access the DummyParser
2497 #[cfg(test)]
2498 pub mod tests {
2499 use super::*;
2500 use crate::builder::SelectorFlags;
2501 use crate::parser;
2502 use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss};
2503 use std::collections::HashMap;
2504 use std::fmt;
2505
2506 #[derive(Clone, Debug, Eq, PartialEq)]
2507 pub enum PseudoClass {
2508 Hover,
2509 Active,
2510 Lang(String),
2511 }
2512
2513 #[derive(Clone, Debug, Eq, PartialEq)]
2514 pub enum PseudoElement {
2515 Before,
2516 After,
2517 }
2518
2519 impl parser::PseudoElement for PseudoElement {
2520 type Impl = DummySelectorImpl;
2521
accepts_state_pseudo_classes(&self) -> bool2522 fn accepts_state_pseudo_classes(&self) -> bool {
2523 true
2524 }
2525
valid_after_slotted(&self) -> bool2526 fn valid_after_slotted(&self) -> bool {
2527 true
2528 }
2529 }
2530
2531 impl parser::NonTSPseudoClass for PseudoClass {
2532 type Impl = DummySelectorImpl;
2533
2534 #[inline]
is_active_or_hover(&self) -> bool2535 fn is_active_or_hover(&self) -> bool {
2536 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
2537 }
2538
2539 #[inline]
is_user_action_state(&self) -> bool2540 fn is_user_action_state(&self) -> bool {
2541 self.is_active_or_hover()
2542 }
2543 }
2544
2545 impl ToCss for PseudoClass {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,2546 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2547 where
2548 W: fmt::Write,
2549 {
2550 match *self {
2551 PseudoClass::Hover => dest.write_str(":hover"),
2552 PseudoClass::Active => dest.write_str(":active"),
2553 PseudoClass::Lang(ref lang) => {
2554 dest.write_str(":lang(")?;
2555 serialize_identifier(lang, dest)?;
2556 dest.write_char(')')
2557 },
2558 }
2559 }
2560 }
2561
2562 impl ToCss for PseudoElement {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,2563 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2564 where
2565 W: fmt::Write,
2566 {
2567 match *self {
2568 PseudoElement::Before => dest.write_str("::before"),
2569 PseudoElement::After => dest.write_str("::after"),
2570 }
2571 }
2572 }
2573
2574 #[derive(Clone, Debug, PartialEq)]
2575 pub struct DummySelectorImpl;
2576
2577 #[derive(Default)]
2578 pub struct DummyParser {
2579 default_ns: Option<DummyAtom>,
2580 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
2581 }
2582
2583 impl DummyParser {
default_with_namespace(default_ns: DummyAtom) -> DummyParser2584 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
2585 DummyParser {
2586 default_ns: Some(default_ns),
2587 ns_prefixes: Default::default(),
2588 }
2589 }
2590 }
2591
2592 impl SelectorImpl for DummySelectorImpl {
2593 type ExtraMatchingData = ();
2594 type AttrValue = DummyAttrValue;
2595 type Identifier = DummyAtom;
2596 type LocalName = DummyAtom;
2597 type NamespaceUrl = DummyAtom;
2598 type NamespacePrefix = DummyAtom;
2599 type BorrowedLocalName = DummyAtom;
2600 type BorrowedNamespaceUrl = DummyAtom;
2601 type NonTSPseudoClass = PseudoClass;
2602 type PseudoElement = PseudoElement;
2603 }
2604
2605 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
2606 pub struct DummyAttrValue(String);
2607
2608 impl ToCss for DummyAttrValue {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,2609 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2610 where
2611 W: fmt::Write,
2612 {
2613 use std::fmt::Write;
2614
2615 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)
2616 }
2617 }
2618
2619 impl<'a> From<&'a str> for DummyAttrValue {
from(string: &'a str) -> Self2620 fn from(string: &'a str) -> Self {
2621 Self(string.into())
2622 }
2623 }
2624
2625 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
2626 pub struct DummyAtom(String);
2627
2628 impl ToCss for DummyAtom {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write,2629 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2630 where
2631 W: fmt::Write,
2632 {
2633 serialize_identifier(&self.0, dest)
2634 }
2635 }
2636
2637 impl From<String> for DummyAtom {
from(string: String) -> Self2638 fn from(string: String) -> Self {
2639 DummyAtom(string)
2640 }
2641 }
2642
2643 impl<'a> From<&'a str> for DummyAtom {
from(string: &'a str) -> Self2644 fn from(string: &'a str) -> Self {
2645 DummyAtom(string.into())
2646 }
2647 }
2648
2649 impl<'i> Parser<'i> for DummyParser {
2650 type Impl = DummySelectorImpl;
2651 type Error = SelectorParseErrorKind<'i>;
2652
parse_slotted(&self) -> bool2653 fn parse_slotted(&self) -> bool {
2654 true
2655 }
2656
parse_is_and_where(&self) -> bool2657 fn parse_is_and_where(&self) -> bool {
2658 true
2659 }
2660
parse_part(&self) -> bool2661 fn parse_part(&self) -> bool {
2662 true
2663 }
2664
parse_non_ts_pseudo_class( &self, location: SourceLocation, name: CowRcStr<'i>, ) -> Result<PseudoClass, SelectorParseError<'i>>2665 fn parse_non_ts_pseudo_class(
2666 &self,
2667 location: SourceLocation,
2668 name: CowRcStr<'i>,
2669 ) -> Result<PseudoClass, SelectorParseError<'i>> {
2670 match_ignore_ascii_case! { &name,
2671 "hover" => return Ok(PseudoClass::Hover),
2672 "active" => return Ok(PseudoClass::Active),
2673 _ => {}
2674 }
2675 Err(
2676 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
2677 name,
2678 )),
2679 )
2680 }
2681
parse_non_ts_functional_pseudo_class<'t>( &self, name: CowRcStr<'i>, parser: &mut CssParser<'i, 't>, ) -> Result<PseudoClass, SelectorParseError<'i>>2682 fn parse_non_ts_functional_pseudo_class<'t>(
2683 &self,
2684 name: CowRcStr<'i>,
2685 parser: &mut CssParser<'i, 't>,
2686 ) -> Result<PseudoClass, SelectorParseError<'i>> {
2687 match_ignore_ascii_case! { &name,
2688 "lang" => {
2689 let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
2690 return Ok(PseudoClass::Lang(lang));
2691 },
2692 _ => {}
2693 }
2694 Err(
2695 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
2696 name,
2697 )),
2698 )
2699 }
2700
parse_pseudo_element( &self, location: SourceLocation, name: CowRcStr<'i>, ) -> Result<PseudoElement, SelectorParseError<'i>>2701 fn parse_pseudo_element(
2702 &self,
2703 location: SourceLocation,
2704 name: CowRcStr<'i>,
2705 ) -> Result<PseudoElement, SelectorParseError<'i>> {
2706 match_ignore_ascii_case! { &name,
2707 "before" => return Ok(PseudoElement::Before),
2708 "after" => return Ok(PseudoElement::After),
2709 _ => {}
2710 }
2711 Err(
2712 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
2713 name,
2714 )),
2715 )
2716 }
2717
default_namespace(&self) -> Option<DummyAtom>2718 fn default_namespace(&self) -> Option<DummyAtom> {
2719 self.default_ns.clone()
2720 }
2721
namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom>2722 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
2723 self.ns_prefixes.get(prefix).cloned()
2724 }
2725 }
2726
parse<'i>( input: &'i str, ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>>2727 fn parse<'i>(
2728 input: &'i str,
2729 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2730 parse_ns(input, &DummyParser::default())
2731 }
2732
parse_expected<'i, 'a>( input: &'i str, expected: Option<&'a str>, ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>>2733 fn parse_expected<'i, 'a>(
2734 input: &'i str,
2735 expected: Option<&'a str>,
2736 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2737 parse_ns_expected(input, &DummyParser::default(), expected)
2738 }
2739
parse_ns<'i>( input: &'i str, parser: &DummyParser, ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>>2740 fn parse_ns<'i>(
2741 input: &'i str,
2742 parser: &DummyParser,
2743 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2744 parse_ns_expected(input, parser, None)
2745 }
2746
parse_ns_expected<'i, 'a>( input: &'i str, parser: &DummyParser, expected: Option<&'a str>, ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>>2747 fn parse_ns_expected<'i, 'a>(
2748 input: &'i str,
2749 parser: &DummyParser,
2750 expected: Option<&'a str>,
2751 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2752 let mut parser_input = ParserInput::new(input);
2753 let result = SelectorList::parse(parser, &mut CssParser::new(&mut parser_input));
2754 if let Ok(ref selectors) = result {
2755 assert_eq!(selectors.0.len(), 1);
2756 // We can't assume that the serialized parsed selector will equal
2757 // the input; for example, if there is no default namespace, '*|foo'
2758 // should serialize to 'foo'.
2759 assert_eq!(
2760 selectors.0[0].to_css_string(),
2761 match expected {
2762 Some(x) => x,
2763 None => input,
2764 }
2765 );
2766 }
2767 result
2768 }
2769
specificity(a: u32, b: u32, c: u32) -> u322770 fn specificity(a: u32, b: u32, c: u32) -> u32 {
2771 a << 20 | b << 10 | c
2772 }
2773
2774 #[test]
test_empty()2775 fn test_empty() {
2776 let mut input = ParserInput::new(":empty");
2777 let list = SelectorList::parse(&DummyParser::default(), &mut CssParser::new(&mut input));
2778 assert!(list.is_ok());
2779 }
2780
2781 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
2782 const SVG: &str = "http://www.w3.org/2000/svg";
2783
2784 #[test]
test_parsing()2785 fn test_parsing() {
2786 assert!(parse("").is_err());
2787 assert!(parse(":lang(4)").is_err());
2788 assert!(parse(":lang(en US)").is_err());
2789 assert_eq!(
2790 parse("EeÉ"),
2791 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2792 vec![Component::LocalName(LocalName {
2793 name: DummyAtom::from("EeÉ"),
2794 lower_name: DummyAtom::from("eeÉ"),
2795 })],
2796 specificity(0, 0, 1),
2797 Default::default(),
2798 )]))
2799 );
2800 assert_eq!(
2801 parse("|e"),
2802 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2803 vec![
2804 Component::ExplicitNoNamespace,
2805 Component::LocalName(LocalName {
2806 name: DummyAtom::from("e"),
2807 lower_name: DummyAtom::from("e"),
2808 }),
2809 ],
2810 specificity(0, 0, 1),
2811 Default::default(),
2812 )]))
2813 );
2814 // When the default namespace is not set, *| should be elided.
2815 // https://github.com/servo/servo/pull/17537
2816 assert_eq!(
2817 parse_expected("*|e", Some("e")),
2818 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2819 vec![Component::LocalName(LocalName {
2820 name: DummyAtom::from("e"),
2821 lower_name: DummyAtom::from("e"),
2822 })],
2823 specificity(0, 0, 1),
2824 Default::default(),
2825 )]))
2826 );
2827 // When the default namespace is set, *| should _not_ be elided (as foo
2828 // is no longer equivalent to *|foo--the former is only for foo in the
2829 // default namespace).
2830 // https://github.com/servo/servo/issues/16020
2831 assert_eq!(
2832 parse_ns(
2833 "*|e",
2834 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
2835 ),
2836 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2837 vec![
2838 Component::ExplicitAnyNamespace,
2839 Component::LocalName(LocalName {
2840 name: DummyAtom::from("e"),
2841 lower_name: DummyAtom::from("e"),
2842 }),
2843 ],
2844 specificity(0, 0, 1),
2845 Default::default(),
2846 )]))
2847 );
2848 assert_eq!(
2849 parse("*"),
2850 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2851 vec![Component::ExplicitUniversalType],
2852 specificity(0, 0, 0),
2853 Default::default(),
2854 )]))
2855 );
2856 assert_eq!(
2857 parse("|*"),
2858 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2859 vec![
2860 Component::ExplicitNoNamespace,
2861 Component::ExplicitUniversalType,
2862 ],
2863 specificity(0, 0, 0),
2864 Default::default(),
2865 )]))
2866 );
2867 assert_eq!(
2868 parse_expected("*|*", Some("*")),
2869 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2870 vec![Component::ExplicitUniversalType],
2871 specificity(0, 0, 0),
2872 Default::default(),
2873 )]))
2874 );
2875 assert_eq!(
2876 parse_ns(
2877 "*|*",
2878 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
2879 ),
2880 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2881 vec![
2882 Component::ExplicitAnyNamespace,
2883 Component::ExplicitUniversalType,
2884 ],
2885 specificity(0, 0, 0),
2886 Default::default(),
2887 )]))
2888 );
2889 assert_eq!(
2890 parse(".foo:lang(en-US)"),
2891 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2892 vec![
2893 Component::Class(DummyAtom::from("foo")),
2894 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
2895 ],
2896 specificity(0, 2, 0),
2897 Default::default(),
2898 )]))
2899 );
2900 assert_eq!(
2901 parse("#bar"),
2902 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2903 vec![Component::ID(DummyAtom::from("bar"))],
2904 specificity(1, 0, 0),
2905 Default::default(),
2906 )]))
2907 );
2908 assert_eq!(
2909 parse("e.foo#bar"),
2910 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2911 vec![
2912 Component::LocalName(LocalName {
2913 name: DummyAtom::from("e"),
2914 lower_name: DummyAtom::from("e"),
2915 }),
2916 Component::Class(DummyAtom::from("foo")),
2917 Component::ID(DummyAtom::from("bar")),
2918 ],
2919 specificity(1, 1, 1),
2920 Default::default(),
2921 )]))
2922 );
2923 assert_eq!(
2924 parse("e.foo #bar"),
2925 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2926 vec![
2927 Component::LocalName(LocalName {
2928 name: DummyAtom::from("e"),
2929 lower_name: DummyAtom::from("e"),
2930 }),
2931 Component::Class(DummyAtom::from("foo")),
2932 Component::Combinator(Combinator::Descendant),
2933 Component::ID(DummyAtom::from("bar")),
2934 ],
2935 specificity(1, 1, 1),
2936 Default::default(),
2937 )]))
2938 );
2939 // Default namespace does not apply to attribute selectors
2940 // https://github.com/mozilla/servo/pull/1652
2941 let mut parser = DummyParser::default();
2942 assert_eq!(
2943 parse_ns("[Foo]", &parser),
2944 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2945 vec![Component::AttributeInNoNamespaceExists {
2946 local_name: DummyAtom::from("Foo"),
2947 local_name_lower: DummyAtom::from("foo"),
2948 }],
2949 specificity(0, 1, 0),
2950 Default::default(),
2951 )]))
2952 );
2953 assert!(parse_ns("svg|circle", &parser).is_err());
2954 parser
2955 .ns_prefixes
2956 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
2957 assert_eq!(
2958 parse_ns("svg|circle", &parser),
2959 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2960 vec![
2961 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
2962 Component::LocalName(LocalName {
2963 name: DummyAtom::from("circle"),
2964 lower_name: DummyAtom::from("circle"),
2965 }),
2966 ],
2967 specificity(0, 0, 1),
2968 Default::default(),
2969 )]))
2970 );
2971 assert_eq!(
2972 parse_ns("svg|*", &parser),
2973 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2974 vec![
2975 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
2976 Component::ExplicitUniversalType,
2977 ],
2978 specificity(0, 0, 0),
2979 Default::default(),
2980 )]))
2981 );
2982 // Default namespace does not apply to attribute selectors
2983 // https://github.com/mozilla/servo/pull/1652
2984 // but it does apply to implicit type selectors
2985 // https://github.com/servo/rust-selectors/pull/82
2986 parser.default_ns = Some(MATHML.into());
2987 assert_eq!(
2988 parse_ns("[Foo]", &parser),
2989 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2990 vec![
2991 Component::DefaultNamespace(MATHML.into()),
2992 Component::AttributeInNoNamespaceExists {
2993 local_name: DummyAtom::from("Foo"),
2994 local_name_lower: DummyAtom::from("foo"),
2995 },
2996 ],
2997 specificity(0, 1, 0),
2998 Default::default(),
2999 )]))
3000 );
3001 // Default namespace does apply to type selectors
3002 assert_eq!(
3003 parse_ns("e", &parser),
3004 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3005 vec![
3006 Component::DefaultNamespace(MATHML.into()),
3007 Component::LocalName(LocalName {
3008 name: DummyAtom::from("e"),
3009 lower_name: DummyAtom::from("e"),
3010 }),
3011 ],
3012 specificity(0, 0, 1),
3013 Default::default(),
3014 )]))
3015 );
3016 assert_eq!(
3017 parse_ns("*", &parser),
3018 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3019 vec![
3020 Component::DefaultNamespace(MATHML.into()),
3021 Component::ExplicitUniversalType,
3022 ],
3023 specificity(0, 0, 0),
3024 Default::default(),
3025 )]))
3026 );
3027 assert_eq!(
3028 parse_ns("*|*", &parser),
3029 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3030 vec![
3031 Component::ExplicitAnyNamespace,
3032 Component::ExplicitUniversalType,
3033 ],
3034 specificity(0, 0, 0),
3035 Default::default(),
3036 )]))
3037 );
3038 // Default namespace applies to universal and type selectors inside :not and :matches,
3039 // but not otherwise.
3040 assert_eq!(
3041 parse_ns(":not(.cl)", &parser),
3042 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3043 vec![
3044 Component::DefaultNamespace(MATHML.into()),
3045 Component::Negation(
3046 vec![Selector::from_vec(
3047 vec![Component::Class(DummyAtom::from("cl"))],
3048 specificity(0, 1, 0),
3049 Default::default(),
3050 )]
3051 .into_boxed_slice()
3052 ),
3053 ],
3054 specificity(0, 1, 0),
3055 Default::default(),
3056 )]))
3057 );
3058 assert_eq!(
3059 parse_ns(":not(*)", &parser),
3060 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3061 vec![
3062 Component::DefaultNamespace(MATHML.into()),
3063 Component::Negation(
3064 vec![Selector::from_vec(
3065 vec![
3066 Component::DefaultNamespace(MATHML.into()),
3067 Component::ExplicitUniversalType,
3068 ],
3069 specificity(0, 0, 0),
3070 Default::default(),
3071 )]
3072 .into_boxed_slice(),
3073 ),
3074 ],
3075 specificity(0, 0, 0),
3076 Default::default(),
3077 )]))
3078 );
3079 assert_eq!(
3080 parse_ns(":not(e)", &parser),
3081 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3082 vec![
3083 Component::DefaultNamespace(MATHML.into()),
3084 Component::Negation(
3085 vec![Selector::from_vec(
3086 vec![
3087 Component::DefaultNamespace(MATHML.into()),
3088 Component::LocalName(LocalName {
3089 name: DummyAtom::from("e"),
3090 lower_name: DummyAtom::from("e"),
3091 }),
3092 ],
3093 specificity(0, 0, 1),
3094 Default::default(),
3095 ),]
3096 .into_boxed_slice()
3097 ),
3098 ],
3099 specificity(0, 0, 1),
3100 Default::default(),
3101 )]))
3102 );
3103 assert_eq!(
3104 parse("[attr|=\"foo\"]"),
3105 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3106 vec![Component::AttributeInNoNamespace {
3107 local_name: DummyAtom::from("attr"),
3108 operator: AttrSelectorOperator::DashMatch,
3109 value: DummyAttrValue::from("foo"),
3110 never_matches: false,
3111 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
3112 }],
3113 specificity(0, 1, 0),
3114 Default::default(),
3115 )]))
3116 );
3117 // https://github.com/mozilla/servo/issues/1723
3118 assert_eq!(
3119 parse("::before"),
3120 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3121 vec![
3122 Component::Combinator(Combinator::PseudoElement),
3123 Component::PseudoElement(PseudoElement::Before),
3124 ],
3125 specificity(0, 0, 1),
3126 SelectorFlags::HAS_PSEUDO,
3127 )]))
3128 );
3129 assert_eq!(
3130 parse("::before:hover"),
3131 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3132 vec![
3133 Component::Combinator(Combinator::PseudoElement),
3134 Component::PseudoElement(PseudoElement::Before),
3135 Component::NonTSPseudoClass(PseudoClass::Hover),
3136 ],
3137 specificity(0, 1, 1),
3138 SelectorFlags::HAS_PSEUDO,
3139 )]))
3140 );
3141 assert_eq!(
3142 parse("::before:hover:hover"),
3143 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3144 vec![
3145 Component::Combinator(Combinator::PseudoElement),
3146 Component::PseudoElement(PseudoElement::Before),
3147 Component::NonTSPseudoClass(PseudoClass::Hover),
3148 Component::NonTSPseudoClass(PseudoClass::Hover),
3149 ],
3150 specificity(0, 2, 1),
3151 SelectorFlags::HAS_PSEUDO,
3152 )]))
3153 );
3154 assert!(parse("::before:hover:lang(foo)").is_err());
3155 assert!(parse("::before:hover .foo").is_err());
3156 assert!(parse("::before .foo").is_err());
3157 assert!(parse("::before ~ bar").is_err());
3158 assert!(parse("::before:active").is_ok());
3159
3160 // https://github.com/servo/servo/issues/15335
3161 assert!(parse(":: before").is_err());
3162 assert_eq!(
3163 parse("div ::after"),
3164 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3165 vec![
3166 Component::LocalName(LocalName {
3167 name: DummyAtom::from("div"),
3168 lower_name: DummyAtom::from("div"),
3169 }),
3170 Component::Combinator(Combinator::Descendant),
3171 Component::Combinator(Combinator::PseudoElement),
3172 Component::PseudoElement(PseudoElement::After),
3173 ],
3174 specificity(0, 0, 2),
3175 SelectorFlags::HAS_PSEUDO,
3176 )]))
3177 );
3178 assert_eq!(
3179 parse("#d1 > .ok"),
3180 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3181 vec![
3182 Component::ID(DummyAtom::from("d1")),
3183 Component::Combinator(Combinator::Child),
3184 Component::Class(DummyAtom::from("ok")),
3185 ],
3186 (1 << 20) + (1 << 10) + (0 << 0),
3187 Default::default(),
3188 )]))
3189 );
3190 parser.default_ns = None;
3191 assert!(parse(":not(#provel.old)").is_ok());
3192 assert!(parse(":not(#provel > old)").is_ok());
3193 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
3194 // https://github.com/servo/servo/issues/16017
3195 assert_eq!(
3196 parse_ns(":not(*)", &parser),
3197 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3198 vec![Component::Negation(
3199 vec![Selector::from_vec(
3200 vec![Component::ExplicitUniversalType],
3201 specificity(0, 0, 0),
3202 Default::default(),
3203 )]
3204 .into_boxed_slice()
3205 )],
3206 specificity(0, 0, 0),
3207 Default::default(),
3208 )]))
3209 );
3210 assert_eq!(
3211 parse_ns(":not(|*)", &parser),
3212 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3213 vec![Component::Negation(
3214 vec![Selector::from_vec(
3215 vec![
3216 Component::ExplicitNoNamespace,
3217 Component::ExplicitUniversalType,
3218 ],
3219 specificity(0, 0, 0),
3220 Default::default(),
3221 )]
3222 .into_boxed_slice(),
3223 )],
3224 specificity(0, 0, 0),
3225 Default::default(),
3226 )]))
3227 );
3228 // *| should be elided if there is no default namespace.
3229 // https://github.com/servo/servo/pull/17537
3230 assert_eq!(
3231 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
3232 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3233 vec![Component::Negation(
3234 vec![Selector::from_vec(
3235 vec![Component::ExplicitUniversalType],
3236 specificity(0, 0, 0),
3237 Default::default()
3238 )]
3239 .into_boxed_slice()
3240 )],
3241 specificity(0, 0, 0),
3242 Default::default(),
3243 )]))
3244 );
3245
3246 assert!(parse("::slotted()").is_err());
3247 assert!(parse("::slotted(div)").is_ok());
3248 assert!(parse("::slotted(div).foo").is_err());
3249 assert!(parse("::slotted(div + bar)").is_err());
3250 assert!(parse("::slotted(div) + foo").is_err());
3251
3252 assert!(parse("::part()").is_err());
3253 assert!(parse("::part(42)").is_err());
3254 assert!(parse("::part(foo bar)").is_ok());
3255 assert!(parse("::part(foo):hover").is_ok());
3256 assert!(parse("::part(foo) + bar").is_err());
3257
3258 assert!(parse("div ::slotted(div)").is_ok());
3259 assert!(parse("div + slot::slotted(div)").is_ok());
3260 assert!(parse("div + slot::slotted(div.foo)").is_ok());
3261 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
3262 assert!(parse("::slotted(div)::before").is_ok());
3263 assert!(parse("slot::slotted(div,foo)").is_err());
3264
3265 assert!(parse("foo:where()").is_ok());
3266 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
3267 assert!(parse_expected("foo:where(::before)", Some("foo:where()")).is_ok());
3268 }
3269
3270 #[test]
test_pseudo_iter()3271 fn test_pseudo_iter() {
3272 let selector = &parse("q::before").unwrap().0[0];
3273 assert!(!selector.is_universal());
3274 let mut iter = selector.iter();
3275 assert_eq!(
3276 iter.next(),
3277 Some(&Component::PseudoElement(PseudoElement::Before))
3278 );
3279 assert_eq!(iter.next(), None);
3280 let combinator = iter.next_sequence();
3281 assert_eq!(combinator, Some(Combinator::PseudoElement));
3282 assert!(matches!(iter.next(), Some(&Component::LocalName(..))));
3283 assert_eq!(iter.next(), None);
3284 assert_eq!(iter.next_sequence(), None);
3285 }
3286
3287 #[test]
test_universal()3288 fn test_universal() {
3289 let selector = &parse_ns(
3290 "*|*::before",
3291 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
3292 )
3293 .unwrap()
3294 .0[0];
3295 assert!(selector.is_universal());
3296 }
3297
3298 #[test]
test_empty_pseudo_iter()3299 fn test_empty_pseudo_iter() {
3300 let selector = &parse("::before").unwrap().0[0];
3301 assert!(selector.is_universal());
3302 let mut iter = selector.iter();
3303 assert_eq!(
3304 iter.next(),
3305 Some(&Component::PseudoElement(PseudoElement::Before))
3306 );
3307 assert_eq!(iter.next(), None);
3308 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
3309 assert_eq!(iter.next(), None);
3310 assert_eq!(iter.next_sequence(), None);
3311 }
3312
3313 struct TestVisitor {
3314 seen: Vec<String>,
3315 }
3316
3317 impl SelectorVisitor for TestVisitor {
3318 type Impl = DummySelectorImpl;
3319
visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool3320 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
3321 let mut dest = String::new();
3322 s.to_css(&mut dest).unwrap();
3323 self.seen.push(dest);
3324 true
3325 }
3326 }
3327
3328 #[test]
visitor()3329 fn visitor() {
3330 let mut test_visitor = TestVisitor { seen: vec![] };
3331 parse(":not(:hover) ~ label").unwrap().0[0].visit(&mut test_visitor);
3332 assert!(test_visitor.seen.contains(&":hover".into()));
3333
3334 let mut test_visitor = TestVisitor { seen: vec![] };
3335 parse("::before:hover").unwrap().0[0].visit(&mut test_visitor);
3336 assert!(test_visitor.seen.contains(&":hover".into()));
3337 }
3338 }
3339