parser.rs (176481B)
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, ParsedCaseSensitivity}; 7 use crate::bloom::BLOOM_HASH_MASK; 8 use crate::builder::{ 9 relative_selector_list_specificity_and_flags, selector_list_specificity_and_flags, 10 SelectorBuilder, SelectorFlags, Specificity, SpecificityAndFlags, 11 }; 12 use crate::context::QuirksMode; 13 use crate::sink::Push; 14 use crate::visitor::SelectorListKind; 15 pub use crate::visitor::SelectorVisitor; 16 use bitflags::bitflags; 17 use cssparser::match_ignore_ascii_case; 18 use cssparser::parse_nth; 19 use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind}; 20 use cssparser::{CowRcStr, Delimiter, SourceLocation}; 21 use cssparser::{Parser as CssParser, ToCss, Token}; 22 use debug_unreachable::debug_unreachable; 23 use precomputed_hash::PrecomputedHash; 24 use servo_arc::{Arc, ArcUnionBorrow, ThinArc, ThinArcUnion, UniqueArc}; 25 use smallvec::SmallVec; 26 use std::borrow::{Borrow, Cow}; 27 use std::fmt::{self, Debug}; 28 use std::iter::Rev; 29 use std::slice; 30 31 #[cfg(feature = "to_shmem")] 32 use to_shmem_derive::ToShmem; 33 34 /// A trait that represents a pseudo-element. 35 pub trait PseudoElement: Sized + ToCss { 36 /// The `SelectorImpl` this pseudo-element is used for. 37 type Impl: SelectorImpl; 38 39 /// Whether the pseudo-element supports a given state selector to the right 40 /// of it. 41 fn accepts_state_pseudo_classes(&self) -> bool { 42 false 43 } 44 45 /// Whether this pseudo-element is valid after a ::slotted(..) pseudo. 46 fn valid_after_slotted(&self) -> bool { 47 false 48 } 49 50 /// Whether this pseudo-element is valid when directly after a ::before/::after pseudo. 51 fn valid_after_before_or_after(&self) -> bool { 52 false 53 } 54 55 /// Whether this pseudo-element is element-backed. 56 /// https://drafts.csswg.org/css-pseudo-4/#element-like 57 fn is_element_backed(&self) -> bool { 58 false 59 } 60 61 /// Whether this pseudo-element is ::before or ::after pseudo element, 62 /// which are treated specially when deciding what can come after them. 63 /// https://drafts.csswg.org/css-pseudo-4/#generated-content 64 fn is_before_or_after(&self) -> bool { 65 false 66 } 67 68 /// The count we contribute to the specificity from this pseudo-element. 69 fn specificity_count(&self) -> u32 { 70 1 71 } 72 73 /// Whether this pseudo-element is in a pseudo-element tree (excluding the pseudo-element 74 /// root). 75 /// https://drafts.csswg.org/css-view-transitions-1/#pseudo-root 76 fn is_in_pseudo_element_tree(&self) -> bool { 77 false 78 } 79 } 80 81 /// A trait that represents a pseudo-class. 82 pub trait NonTSPseudoClass: Sized + ToCss { 83 /// The `SelectorImpl` this pseudo-element is used for. 84 type Impl: SelectorImpl; 85 86 /// Whether this pseudo-class is :active or :hover. 87 fn is_active_or_hover(&self) -> bool; 88 89 /// Whether this pseudo-class belongs to: 90 /// 91 /// https://drafts.csswg.org/selectors-4/#useraction-pseudos 92 fn is_user_action_state(&self) -> bool; 93 94 fn visit<V>(&self, _visitor: &mut V) -> bool 95 where 96 V: SelectorVisitor<Impl = Self::Impl>, 97 { 98 true 99 } 100 } 101 102 /// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a 103 /// Cow::Owned if `s` had to be converted into ASCII lowercase. 104 fn to_ascii_lowercase(s: &str) -> Cow<'_, str> { 105 if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') { 106 let mut string = s.to_owned(); 107 string[first_uppercase..].make_ascii_lowercase(); 108 string.into() 109 } else { 110 s.into() 111 } 112 } 113 114 bitflags! { 115 /// Flags that indicate at which point of parsing a selector are we. 116 #[derive(Copy, Clone)] 117 struct SelectorParsingState: u16 { 118 /// Whether we should avoid adding default namespaces to selectors that 119 /// aren't type or universal selectors. 120 const SKIP_DEFAULT_NAMESPACE = 1 << 0; 121 122 /// Whether we've parsed a ::slotted() pseudo-element already. 123 /// 124 /// If so, then we can only parse a subset of pseudo-elements, and 125 /// whatever comes after them if so. 126 const AFTER_SLOTTED = 1 << 1; 127 /// Whether we've parsed a ::part() or element-backed pseudo-element already. 128 /// 129 /// If so, then we can only parse a subset of pseudo-elements, and 130 /// whatever comes after them if so. 131 const AFTER_PART_LIKE = 1 << 2; 132 /// Whether we've parsed a non-element-backed pseudo-element (as in, an 133 /// `Impl::PseudoElement` thus not accounting for `::slotted` or 134 /// `::part`) already. 135 /// 136 /// If so, then other pseudo-elements and most other selectors are 137 /// disallowed. 138 const AFTER_NON_ELEMENT_BACKED_PSEUDO = 1 << 3; 139 /// Whether we've parsed a non-stateful pseudo-element (again, as-in 140 /// `Impl::PseudoElement`) already. If so, then other pseudo-classes are 141 /// disallowed. If this flag is set, `AFTER_NON_ELEMENT_BACKED_PSEUDO` must be set 142 /// as well. 143 const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4; 144 // Whether we've parsed a generated pseudo-element (as in ::before, ::after). 145 // If so then some other pseudo elements are disallowed (e.g. another generated pseudo) 146 // while others allowed (e.g. ::marker). 147 const AFTER_BEFORE_OR_AFTER_PSEUDO = 1 << 5; 148 149 /// Whether we are after any of the pseudo-like things. 150 const AFTER_PSEUDO = Self::AFTER_PART_LIKE.bits() | Self::AFTER_SLOTTED.bits() | Self::AFTER_NON_ELEMENT_BACKED_PSEUDO.bits() | Self::AFTER_BEFORE_OR_AFTER_PSEUDO.bits(); 151 152 /// Whether we explicitly disallow combinators. 153 const DISALLOW_COMBINATORS = 1 << 6; 154 155 /// Whether we explicitly disallow pseudo-element-like things. 156 const DISALLOW_PSEUDOS = 1 << 7; 157 158 /// Whether we explicitly disallow relative selectors (i.e. `:has()`). 159 const DISALLOW_RELATIVE_SELECTOR = 1 << 8; 160 161 /// Whether we've parsed a pseudo-element which is in a pseudo-element tree (i.e. it is a 162 /// descendant pseudo of a pseudo-element root). 163 const IN_PSEUDO_ELEMENT_TREE = 1 << 9; 164 } 165 } 166 167 impl SelectorParsingState { 168 #[inline] 169 fn allows_slotted(self) -> bool { 170 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS) 171 } 172 173 #[inline] 174 fn allows_part(self) -> bool { 175 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS) 176 } 177 178 #[inline] 179 fn allows_non_functional_pseudo_classes(self) -> bool { 180 !self.intersects(Self::AFTER_SLOTTED | Self::AFTER_NON_STATEFUL_PSEUDO_ELEMENT) 181 } 182 183 #[inline] 184 fn allows_tree_structural_pseudo_classes(self) -> bool { 185 !self.intersects(Self::AFTER_PSEUDO) || self.intersects(Self::IN_PSEUDO_ELEMENT_TREE) 186 } 187 188 #[inline] 189 fn allows_combinators(self) -> bool { 190 !self.intersects(Self::DISALLOW_COMBINATORS) 191 } 192 193 #[inline] 194 fn allows_only_child_pseudo_class_only(self) -> bool { 195 self.intersects(Self::IN_PSEUDO_ELEMENT_TREE) 196 } 197 } 198 199 pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>; 200 201 #[derive(Clone, Debug, PartialEq)] 202 pub enum SelectorParseErrorKind<'i> { 203 NoQualifiedNameInAttributeSelector(Token<'i>), 204 EmptySelector, 205 DanglingCombinator, 206 NonCompoundSelector, 207 NonPseudoElementAfterSlotted, 208 InvalidPseudoElementAfterSlotted, 209 InvalidPseudoElementInsideWhere, 210 InvalidState, 211 UnexpectedTokenInAttributeSelector(Token<'i>), 212 PseudoElementExpectedColon(Token<'i>), 213 PseudoElementExpectedIdent(Token<'i>), 214 NoIdentForPseudo(Token<'i>), 215 UnsupportedPseudoClassOrElement(CowRcStr<'i>), 216 UnexpectedIdent(CowRcStr<'i>), 217 ExpectedNamespace(CowRcStr<'i>), 218 ExpectedBarInAttr(Token<'i>), 219 BadValueInAttr(Token<'i>), 220 InvalidQualNameInAttr(Token<'i>), 221 ExplicitNamespaceUnexpectedToken(Token<'i>), 222 ClassNeedsIdent(Token<'i>), 223 } 224 225 macro_rules! with_all_bounds { 226 ( 227 [ $( $InSelector: tt )* ] 228 [ $( $CommonBounds: tt )* ] 229 [ $( $FromStr: tt )* ] 230 ) => { 231 /// This trait allows to define the parser implementation in regards 232 /// of pseudo-classes/elements 233 /// 234 /// NB: We need Clone so that we can derive(Clone) on struct with that 235 /// are parameterized on SelectorImpl. See 236 /// <https://github.com/rust-lang/rust/issues/26925> 237 pub trait SelectorImpl: Clone + Debug + Sized + 'static { 238 type ExtraMatchingData<'a>: Sized + Default; 239 type AttrValue: $($InSelector)*; 240 type Identifier: $($InSelector)* + PrecomputedHash; 241 type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName> + PrecomputedHash; 242 type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl> + PrecomputedHash; 243 type NamespacePrefix: $($InSelector)* + Default; 244 type BorrowedNamespaceUrl: ?Sized + Eq; 245 type BorrowedLocalName: ?Sized + Eq; 246 247 /// non tree-structural pseudo-classes 248 /// (see: https://drafts.csswg.org/selectors/#structural-pseudos) 249 type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass<Impl = Self>; 250 251 /// pseudo-elements 252 type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>; 253 254 /// Whether attribute hashes should be collected for filtering 255 /// purposes. 256 fn should_collect_attr_hash(_name: &Self::LocalName) -> bool { 257 false 258 } 259 } 260 } 261 } 262 263 macro_rules! with_bounds { 264 ( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => { 265 with_all_bounds! { 266 [$($CommonBounds)* + $($FromStr)* + ToCss] 267 [$($CommonBounds)*] 268 [$($FromStr)*] 269 } 270 } 271 } 272 273 with_bounds! { 274 [Clone + Eq] 275 [for<'a> From<&'a str>] 276 } 277 278 pub trait Parser<'i> { 279 type Impl: SelectorImpl; 280 type Error: 'i + From<SelectorParseErrorKind<'i>>; 281 282 /// Whether to parse the `::slotted()` pseudo-element. 283 fn parse_slotted(&self) -> bool { 284 false 285 } 286 287 /// Whether to parse the `::part()` pseudo-element. 288 fn parse_part(&self) -> bool { 289 false 290 } 291 292 /// Whether to parse the selector list of nth-child() or nth-last-child(). 293 fn parse_nth_child_of(&self) -> bool { 294 false 295 } 296 297 /// Whether to parse `:is` and `:where` pseudo-classes. 298 fn parse_is_and_where(&self) -> bool { 299 false 300 } 301 302 /// Whether to parse the :has pseudo-class. 303 fn parse_has(&self) -> bool { 304 false 305 } 306 307 /// Whether to parse the '&' delimiter as a parent selector. 308 fn parse_parent_selector(&self) -> bool { 309 false 310 } 311 312 /// Whether the given function name is an alias for the `:is()` function. 313 fn is_is_alias(&self, _name: &str) -> bool { 314 false 315 } 316 317 /// Whether to parse the `:host` pseudo-class. 318 fn parse_host(&self) -> bool { 319 false 320 } 321 322 /// Whether to allow forgiving selector-list parsing. 323 fn allow_forgiving_selectors(&self) -> bool { 324 true 325 } 326 327 /// This function can return an "Err" pseudo-element in order to support CSS2.1 328 /// pseudo-elements. 329 fn parse_non_ts_pseudo_class( 330 &self, 331 location: SourceLocation, 332 name: CowRcStr<'i>, 333 ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> { 334 Err( 335 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 336 name, 337 )), 338 ) 339 } 340 341 fn parse_non_ts_functional_pseudo_class<'t>( 342 &self, 343 name: CowRcStr<'i>, 344 parser: &mut CssParser<'i, 't>, 345 _after_part: bool, 346 ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> { 347 Err( 348 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 349 name, 350 )), 351 ) 352 } 353 354 fn parse_pseudo_element( 355 &self, 356 location: SourceLocation, 357 name: CowRcStr<'i>, 358 ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> { 359 Err( 360 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 361 name, 362 )), 363 ) 364 } 365 366 fn parse_functional_pseudo_element<'t>( 367 &self, 368 name: CowRcStr<'i>, 369 arguments: &mut CssParser<'i, 't>, 370 ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> { 371 Err( 372 arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 373 name, 374 )), 375 ) 376 } 377 378 fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> { 379 None 380 } 381 382 fn namespace_for_prefix( 383 &self, 384 _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix, 385 ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> { 386 None 387 } 388 } 389 390 /// A selector list is a tagged pointer with either a single selector, or a ThinArc<()> of multiple 391 /// selectors. 392 #[derive(Clone, Eq, Debug, PartialEq)] 393 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 394 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 395 pub struct SelectorList<Impl: SelectorImpl>( 396 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] 397 ThinArcUnion<SpecificityAndFlags, Component<Impl>, (), Selector<Impl>>, 398 ); 399 400 impl<Impl: SelectorImpl> SelectorList<Impl> { 401 /// See Arc::mark_as_intentionally_leaked 402 pub fn mark_as_intentionally_leaked(&self) { 403 if let ArcUnionBorrow::Second(ref list) = self.0.borrow() { 404 list.with_arc(|list| list.mark_as_intentionally_leaked()) 405 } 406 self.slice() 407 .iter() 408 .for_each(|s| s.mark_as_intentionally_leaked()) 409 } 410 411 pub fn from_one(selector: Selector<Impl>) -> Self { 412 #[cfg(debug_assertions)] 413 let selector_repr = unsafe { *(&selector as *const _ as *const usize) }; 414 let list = Self(ThinArcUnion::from_first(selector.into_data())); 415 #[cfg(debug_assertions)] 416 debug_assert_eq!( 417 selector_repr, 418 unsafe { *(&list as *const _ as *const usize) }, 419 "We rely on the same bit representation for the single selector variant" 420 ); 421 list 422 } 423 424 pub fn from_iter(mut iter: impl ExactSizeIterator<Item = Selector<Impl>>) -> Self { 425 if iter.len() == 1 { 426 Self::from_one(iter.next().unwrap()) 427 } else { 428 Self(ThinArcUnion::from_second(ThinArc::from_header_and_iter( 429 (), 430 iter, 431 ))) 432 } 433 } 434 435 #[inline] 436 pub fn slice(&self) -> &[Selector<Impl>] { 437 match self.0.borrow() { 438 ArcUnionBorrow::First(..) => { 439 // SAFETY: see from_one. 440 let selector: &Selector<Impl> = unsafe { std::mem::transmute(self) }; 441 std::slice::from_ref(selector) 442 }, 443 ArcUnionBorrow::Second(list) => list.get().slice(), 444 } 445 } 446 447 #[inline] 448 pub fn len(&self) -> usize { 449 match self.0.borrow() { 450 ArcUnionBorrow::First(..) => 1, 451 ArcUnionBorrow::Second(list) => list.len(), 452 } 453 } 454 455 /// Returns the address on the heap of the ThinArc for memory reporting. 456 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void { 457 match self.0.borrow() { 458 ArcUnionBorrow::First(s) => s.with_arc(|a| a.heap_ptr()), 459 ArcUnionBorrow::Second(s) => s.with_arc(|a| a.heap_ptr()), 460 } 461 } 462 } 463 464 /// Uniquely identify a selector based on its components, which is behind ThinArc and 465 /// is therefore stable. 466 #[derive(Clone, Copy, Hash, Eq, PartialEq)] 467 pub struct SelectorKey(usize); 468 469 impl SelectorKey { 470 /// Create a new key based on the given selector. 471 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>) -> Self { 472 Self(selector.0.slice().as_ptr() as usize) 473 } 474 } 475 476 /// Whether or not we're using forgiving parsing mode 477 #[derive(PartialEq)] 478 enum ForgivingParsing { 479 /// Discard the entire selector list upon encountering any invalid selector. 480 /// This is the default behavior for almost all of CSS. 481 No, 482 /// Ignore invalid selectors, potentially creating an empty selector list. 483 /// 484 /// This is the error recovery mode of :is() and :where() 485 Yes, 486 } 487 488 /// Flag indicating if we're parsing relative selectors. 489 #[derive(Copy, Clone, PartialEq)] 490 pub enum ParseRelative { 491 /// Expect selectors to start with a combinator, assuming descendant combinator if not present. 492 ForHas, 493 /// Allow selectors to start with a combinator, prepending a parent selector if so. Do nothing 494 /// otherwise 495 ForNesting, 496 /// Allow selectors to start with a combinator, prepending a scope selector if so. Do nothing 497 /// otherwise 498 ForScope, 499 /// Treat as parse error if any selector begins with a combinator. 500 No, 501 } 502 503 impl<Impl: SelectorImpl> SelectorList<Impl> { 504 /// Returns a selector list with a single `:scope` selector (with specificity) 505 pub fn scope() -> Self { 506 Self::from_one(Selector::scope()) 507 } 508 /// Returns a selector list with a single implicit `:scope` selector (no specificity) 509 pub fn implicit_scope() -> Self { 510 Self::from_one(Selector::implicit_scope()) 511 } 512 513 /// Parse a comma-separated list of Selectors. 514 /// <https://drafts.csswg.org/selectors/#grouping> 515 /// 516 /// Return the Selectors or Err if there is an invalid selector. 517 pub fn parse<'i, 't, P>( 518 parser: &P, 519 input: &mut CssParser<'i, 't>, 520 parse_relative: ParseRelative, 521 ) -> Result<Self, ParseError<'i, P::Error>> 522 where 523 P: Parser<'i, Impl = Impl>, 524 { 525 Self::parse_with_state( 526 parser, 527 input, 528 SelectorParsingState::empty(), 529 ForgivingParsing::No, 530 parse_relative, 531 ) 532 } 533 534 /// Same as `parse`, but disallow parsing of pseudo-elements. 535 pub fn parse_disallow_pseudo<'i, 't, P>( 536 parser: &P, 537 input: &mut CssParser<'i, 't>, 538 parse_relative: ParseRelative, 539 ) -> Result<Self, ParseError<'i, P::Error>> 540 where 541 P: Parser<'i, Impl = Impl>, 542 { 543 Self::parse_with_state( 544 parser, 545 input, 546 SelectorParsingState::DISALLOW_PSEUDOS, 547 ForgivingParsing::No, 548 parse_relative, 549 ) 550 } 551 552 pub fn parse_forgiving<'i, 't, P>( 553 parser: &P, 554 input: &mut CssParser<'i, 't>, 555 parse_relative: ParseRelative, 556 ) -> Result<Self, ParseError<'i, P::Error>> 557 where 558 P: Parser<'i, Impl = Impl>, 559 { 560 Self::parse_with_state( 561 parser, 562 input, 563 SelectorParsingState::empty(), 564 ForgivingParsing::Yes, 565 parse_relative, 566 ) 567 } 568 569 #[inline] 570 fn parse_with_state<'i, 't, P>( 571 parser: &P, 572 input: &mut CssParser<'i, 't>, 573 state: SelectorParsingState, 574 recovery: ForgivingParsing, 575 parse_relative: ParseRelative, 576 ) -> Result<Self, ParseError<'i, P::Error>> 577 where 578 P: Parser<'i, Impl = Impl>, 579 { 580 let mut values = SmallVec::<[_; 4]>::new(); 581 let forgiving = recovery == ForgivingParsing::Yes && parser.allow_forgiving_selectors(); 582 loop { 583 let selector = input.parse_until_before(Delimiter::Comma, |input| { 584 let start = input.position(); 585 let mut selector = parse_selector(parser, input, state, parse_relative); 586 if forgiving && (selector.is_err() || input.expect_exhausted().is_err()) { 587 input.expect_no_error_token()?; 588 selector = Ok(Selector::new_invalid(input.slice_from(start))); 589 } 590 selector 591 })?; 592 593 values.push(selector); 594 595 match input.next() { 596 Ok(&Token::Comma) => {}, 597 Ok(_) => unreachable!(), 598 Err(_) => break, 599 } 600 } 601 Ok(Self::from_iter(values.into_iter())) 602 } 603 604 /// Replaces the parent selector in all the items of the selector list. 605 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self { 606 Self::from_iter( 607 self.slice() 608 .iter() 609 .map(|selector| selector.replace_parent_selector(parent)), 610 ) 611 } 612 613 /// Creates a SelectorList from a Vec of selectors. Used in tests. 614 #[allow(dead_code)] 615 pub(crate) fn from_vec(v: Vec<Selector<Impl>>) -> Self { 616 SelectorList::from_iter(v.into_iter()) 617 } 618 } 619 620 /// Parses one compound selector suitable for nested stuff like :-moz-any, etc. 621 fn parse_inner_compound_selector<'i, 't, P, Impl>( 622 parser: &P, 623 input: &mut CssParser<'i, 't>, 624 state: SelectorParsingState, 625 ) -> Result<Selector<Impl>, ParseError<'i, P::Error>> 626 where 627 P: Parser<'i, Impl = Impl>, 628 Impl: SelectorImpl, 629 { 630 parse_selector( 631 parser, 632 input, 633 state | SelectorParsingState::DISALLOW_PSEUDOS | SelectorParsingState::DISALLOW_COMBINATORS, 634 ParseRelative::No, 635 ) 636 } 637 638 /// Ancestor hashes for the bloom filter. We precompute these and store them 639 /// inline with selectors to optimize cache performance during matching. 640 /// This matters a lot. 641 /// 642 /// We use 4 hashes, which is copied from Gecko, who copied it from WebKit. 643 /// Note that increasing the number of hashes here will adversely affect the 644 /// cache hit when fast-rejecting long lists of Rules with inline hashes. 645 /// 646 /// Because the bloom filter only uses the bottom 24 bits of the hash, we pack 647 /// the fourth hash into the upper bits of the first three hashes in order to 648 /// shrink Rule (whose size matters a lot). This scheme minimizes the runtime 649 /// overhead of the packing for the first three hashes (we just need to mask 650 /// off the upper bits) at the expense of making the fourth somewhat more 651 /// complicated to assemble, because we often bail out before checking all the 652 /// hashes. 653 #[derive(Clone, Debug, Eq, PartialEq)] 654 pub struct AncestorHashes { 655 pub packed_hashes: [u32; 3], 656 } 657 658 pub(crate) fn collect_selector_hashes<'a, Impl: SelectorImpl, Iter>( 659 iter: Iter, 660 quirks_mode: QuirksMode, 661 hashes: &mut [u32; 4], 662 len: &mut usize, 663 create_inner_iterator: fn(&'a Selector<Impl>) -> Iter, 664 ) -> bool 665 where 666 Iter: Iterator<Item = &'a Component<Impl>>, 667 { 668 for component in iter { 669 let hash = match *component { 670 Component::LocalName(LocalName { 671 ref name, 672 ref lower_name, 673 }) => { 674 // Only insert the local-name into the filter if it's all 675 // lowercase. Otherwise we would need to test both hashes, and 676 // our data structures aren't really set up for that. 677 if name != lower_name { 678 continue; 679 } 680 name.precomputed_hash() 681 }, 682 Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => { 683 url.precomputed_hash() 684 }, 685 // In quirks mode, class and id selectors should match 686 // case-insensitively, so just avoid inserting them into the filter. 687 Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => id.precomputed_hash(), 688 Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => { 689 class.precomputed_hash() 690 }, 691 Component::AttributeInNoNamespace { ref local_name, .. } 692 if Impl::should_collect_attr_hash(local_name) => 693 { 694 // AttributeInNoNamespace is only used when local_name == 695 // local_name_lower. 696 local_name.precomputed_hash() 697 }, 698 Component::AttributeInNoNamespaceExists { 699 ref local_name, 700 ref local_name_lower, 701 .. 702 } => { 703 // Only insert the local-name into the filter if it's all 704 // lowercase. Otherwise we would need to test both hashes, and 705 // our data structures aren't really set up for that. 706 if local_name != local_name_lower || !Impl::should_collect_attr_hash(local_name) { 707 continue; 708 } 709 local_name.precomputed_hash() 710 }, 711 Component::AttributeOther(ref selector) => { 712 if selector.local_name != selector.local_name_lower 713 || !Impl::should_collect_attr_hash(&selector.local_name) 714 { 715 continue; 716 } 717 selector.local_name.precomputed_hash() 718 }, 719 Component::Is(ref list) | Component::Where(ref list) => { 720 // :where and :is OR their selectors, so we can't put any hash 721 // in the filter if there's more than one selector, as that'd 722 // exclude elements that may match one of the other selectors. 723 let slice = list.slice(); 724 if slice.len() == 1 725 && !collect_selector_hashes( 726 create_inner_iterator(&slice[0]), 727 quirks_mode, 728 hashes, 729 len, 730 create_inner_iterator, 731 ) 732 { 733 return false; 734 } 735 continue; 736 }, 737 _ => continue, 738 }; 739 740 hashes[*len] = hash & BLOOM_HASH_MASK; 741 *len += 1; 742 if *len == hashes.len() { 743 return false; 744 } 745 } 746 true 747 } 748 749 fn collect_ancestor_hashes<Impl: SelectorImpl>( 750 iter: SelectorIter<Impl>, 751 quirks_mode: QuirksMode, 752 hashes: &mut [u32; 4], 753 len: &mut usize, 754 ) { 755 collect_selector_hashes(AncestorIter::new(iter), quirks_mode, hashes, len, |s| { 756 AncestorIter(s.iter()) 757 }); 758 } 759 760 impl AncestorHashes { 761 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self { 762 // Compute ancestor hashes for the bloom filter. 763 let mut hashes = [0u32; 4]; 764 let mut len = 0; 765 collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len); 766 debug_assert!(len <= 4); 767 768 // Now, pack the fourth hash (if it exists) into the upper byte of each of 769 // the other three hashes. 770 if len == 4 { 771 let fourth = hashes[3]; 772 hashes[0] |= (fourth & 0x000000ff) << 24; 773 hashes[1] |= (fourth & 0x0000ff00) << 16; 774 hashes[2] |= (fourth & 0x00ff0000) << 8; 775 } 776 777 AncestorHashes { 778 packed_hashes: [hashes[0], hashes[1], hashes[2]], 779 } 780 } 781 782 /// Returns the fourth hash, reassembled from parts. 783 pub fn fourth_hash(&self) -> u32 { 784 ((self.packed_hashes[0] & 0xff000000) >> 24) 785 | ((self.packed_hashes[1] & 0xff000000) >> 16) 786 | ((self.packed_hashes[2] & 0xff000000) >> 8) 787 } 788 } 789 790 #[inline] 791 pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl { 792 // Rust type’s default, not default namespace 793 Impl::NamespaceUrl::default() 794 } 795 796 pub(super) type SelectorData<Impl> = ThinArc<SpecificityAndFlags, Component<Impl>>; 797 798 /// Whether a selector may match a featureless host element, and whether it may match other 799 /// elements. 800 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 801 pub enum MatchesFeaturelessHost { 802 /// The selector may match a featureless host, but also a non-featureless element. 803 Yes, 804 /// The selector is guaranteed to never match a non-featureless host element. 805 Only, 806 /// The selector never matches a featureless host. 807 Never, 808 } 809 810 impl MatchesFeaturelessHost { 811 /// Whether we may match. 812 #[inline] 813 pub fn may_match(self) -> bool { 814 return !matches!(self, Self::Never); 815 } 816 } 817 818 /// A Selector stores a sequence of simple selectors and combinators. The 819 /// iterator classes allow callers to iterate at either the raw sequence level or 820 /// at the level of sequences of simple selectors separated by combinators. Most 821 /// callers want the higher-level iterator. 822 /// 823 /// We store compound selectors internally right-to-left (in matching order). 824 /// Additionally, we invert the order of top-level compound selectors so that 825 /// each one matches left-to-right. This is because matching namespace, local name, 826 /// id, and class are all relatively cheap, whereas matching pseudo-classes might 827 /// be expensive (depending on the pseudo-class). Since authors tend to put the 828 /// pseudo-classes on the right, it's faster to start matching on the left. 829 /// 830 /// This reordering doesn't change the semantics of selector matching, and we 831 /// handle it in to_css to make it invisible to serialization. 832 #[derive(Clone, Eq, PartialEq)] 833 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 834 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 835 #[repr(transparent)] 836 pub struct Selector<Impl: SelectorImpl>( 837 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] SelectorData<Impl>, 838 ); 839 840 impl<Impl: SelectorImpl> Selector<Impl> { 841 /// See Arc::mark_as_intentionally_leaked 842 pub fn mark_as_intentionally_leaked(&self) { 843 self.0.mark_as_intentionally_leaked() 844 } 845 846 fn scope() -> Self { 847 Self(ThinArc::from_header_and_iter( 848 SpecificityAndFlags { 849 specificity: Specificity::single_class_like().into(), 850 flags: SelectorFlags::HAS_SCOPE, 851 }, 852 std::iter::once(Component::Scope), 853 )) 854 } 855 856 /// An implicit scope selector, much like :where(:scope). 857 fn implicit_scope() -> Self { 858 Self(ThinArc::from_header_and_iter( 859 SpecificityAndFlags { 860 specificity: 0, 861 flags: SelectorFlags::HAS_SCOPE, 862 }, 863 std::iter::once(Component::ImplicitScope), 864 )) 865 } 866 867 #[inline] 868 pub fn specificity(&self) -> u32 { 869 self.0.header.specificity 870 } 871 872 #[inline] 873 pub(crate) fn flags(&self) -> SelectorFlags { 874 self.0.header.flags 875 } 876 877 #[inline] 878 pub fn has_pseudo_element(&self) -> bool { 879 self.flags().intersects(SelectorFlags::HAS_PSEUDO) 880 } 881 882 #[inline] 883 pub fn has_parent_selector(&self) -> bool { 884 self.flags().intersects(SelectorFlags::HAS_PARENT) 885 } 886 887 #[inline] 888 pub fn has_scope_selector(&self) -> bool { 889 self.flags().intersects(SelectorFlags::HAS_SCOPE) 890 } 891 892 #[inline] 893 pub fn is_slotted(&self) -> bool { 894 self.flags().intersects(SelectorFlags::HAS_SLOTTED) 895 } 896 897 #[inline] 898 pub fn is_part(&self) -> bool { 899 self.flags().intersects(SelectorFlags::HAS_PART) 900 } 901 902 #[inline] 903 pub fn parts(&self) -> Option<&[Impl::Identifier]> { 904 if !self.is_part() { 905 return None; 906 } 907 908 let mut iter = self.iter(); 909 if self.has_pseudo_element() { 910 // Skip the pseudo-element. 911 for _ in &mut iter {} 912 913 let combinator = iter.next_sequence()?; 914 debug_assert_eq!(combinator, Combinator::PseudoElement); 915 } 916 917 for component in iter { 918 if let Component::Part(ref part) = *component { 919 return Some(part); 920 } 921 } 922 923 debug_assert!(false, "is_part() lied somehow?"); 924 None 925 } 926 927 #[inline] 928 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> { 929 if !self.has_pseudo_element() { 930 return None; 931 } 932 933 for component in self.iter() { 934 if let Component::PseudoElement(ref pseudo) = *component { 935 return Some(pseudo); 936 } 937 } 938 939 debug_assert!(false, "has_pseudo_element lied!"); 940 None 941 } 942 943 #[inline] 944 pub fn pseudo_elements(&self) -> SmallVec<[&Impl::PseudoElement; 3]> { 945 let mut pseudos = SmallVec::new(); 946 947 if !self.has_pseudo_element() { 948 return pseudos; 949 } 950 951 let mut iter = self.iter(); 952 loop { 953 for component in &mut iter { 954 if let Component::PseudoElement(ref pseudo) = *component { 955 pseudos.push(pseudo); 956 } 957 } 958 match iter.next_sequence() { 959 Some(Combinator::PseudoElement) => {}, 960 _ => break, 961 } 962 } 963 964 debug_assert!(!pseudos.is_empty(), "has_pseudo_element lied!"); 965 966 pseudos 967 } 968 969 /// Whether this selector (pseudo-element part excluded) matches every element. 970 /// 971 /// Used for "pre-computed" pseudo-elements in components/style/stylist.rs 972 #[inline] 973 pub fn is_universal(&self) -> bool { 974 self.iter_raw_match_order().all(|c| { 975 matches!( 976 *c, 977 Component::ExplicitUniversalType 978 | Component::ExplicitAnyNamespace 979 | Component::Combinator(Combinator::PseudoElement) 980 | Component::PseudoElement(..) 981 ) 982 }) 983 } 984 985 /// Whether this selector may match a featureless shadow host, with no combinators to the 986 /// left, and optionally has a pseudo-element to the right. 987 #[inline] 988 pub fn matches_featureless_host( 989 &self, 990 scope_matches_featureless_host: bool, 991 ) -> MatchesFeaturelessHost { 992 let flags = self.flags(); 993 if !flags.intersects(SelectorFlags::HAS_HOST | SelectorFlags::HAS_SCOPE) { 994 return MatchesFeaturelessHost::Never; 995 } 996 997 let mut iter = self.iter(); 998 if flags.intersects(SelectorFlags::HAS_PSEUDO) { 999 for _ in &mut iter { 1000 // Skip over pseudo-elements 1001 } 1002 match iter.next_sequence() { 1003 Some(c) if c.is_pseudo_element() => {}, 1004 _ => { 1005 debug_assert!(false, "Pseudo selector without pseudo combinator?"); 1006 return MatchesFeaturelessHost::Never; 1007 }, 1008 } 1009 } 1010 1011 let compound_matches = crate::matching::compound_matches_featureless_host( 1012 &mut iter, 1013 scope_matches_featureless_host, 1014 ); 1015 if iter.next_sequence().is_some() { 1016 return MatchesFeaturelessHost::Never; 1017 } 1018 return compound_matches; 1019 } 1020 1021 /// Returns an iterator over this selector in matching order (right-to-left). 1022 /// When a combinator is reached, the iterator will return None, and 1023 /// next_sequence() may be called to continue to the next sequence. 1024 #[inline] 1025 pub fn iter(&self) -> SelectorIter<'_, Impl> { 1026 SelectorIter { 1027 iter: self.iter_raw_match_order(), 1028 next_combinator: None, 1029 } 1030 } 1031 1032 /// Same as `iter()`, but skips `RelativeSelectorAnchor` and its associated combinator. 1033 #[inline] 1034 pub fn iter_skip_relative_selector_anchor(&self) -> SelectorIter<'_, Impl> { 1035 if cfg!(debug_assertions) { 1036 let mut selector_iter = self.iter_raw_parse_order_from(0); 1037 assert!( 1038 matches!( 1039 selector_iter.next().unwrap(), 1040 Component::RelativeSelectorAnchor 1041 ), 1042 "Relative selector does not start with RelativeSelectorAnchor" 1043 ); 1044 assert!( 1045 selector_iter.next().unwrap().is_combinator(), 1046 "Relative combinator does not exist" 1047 ); 1048 } 1049 1050 SelectorIter { 1051 iter: self.0.slice()[..self.len() - 2].iter(), 1052 next_combinator: None, 1053 } 1054 } 1055 1056 /// Returns an iterator over this selector in matching order (right-to-left), 1057 /// skipping the rightmost |offset| Components. 1058 #[inline] 1059 pub fn iter_from(&self, offset: usize) -> SelectorIter<'_, Impl> { 1060 let iter = self.0.slice()[offset..].iter(); 1061 SelectorIter { 1062 iter, 1063 next_combinator: None, 1064 } 1065 } 1066 1067 /// Returns the combinator at index `index` (zero-indexed from the right), 1068 /// or panics if the component is not a combinator. 1069 #[inline] 1070 pub fn combinator_at_match_order(&self, index: usize) -> Combinator { 1071 match self.0.slice()[index] { 1072 Component::Combinator(c) => c, 1073 ref other => panic!( 1074 "Not a combinator: {:?}, {:?}, index: {}", 1075 other, self, index 1076 ), 1077 } 1078 } 1079 1080 /// Returns an iterator over the entire sequence of simple selectors and 1081 /// combinators, in matching order (from right to left). 1082 #[inline] 1083 pub fn iter_raw_match_order(&self) -> slice::Iter<'_, Component<Impl>> { 1084 self.0.slice().iter() 1085 } 1086 1087 /// Returns the combinator at index `index` (zero-indexed from the left), 1088 /// or panics if the component is not a combinator. 1089 #[inline] 1090 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator { 1091 match self.0.slice()[self.len() - index - 1] { 1092 Component::Combinator(c) => c, 1093 ref other => panic!( 1094 "Not a combinator: {:?}, {:?}, index: {}", 1095 other, self, index 1096 ), 1097 } 1098 } 1099 1100 /// Returns an iterator over the sequence of simple selectors and 1101 /// combinators, in parse order (from left to right), starting from 1102 /// `offset`. 1103 #[inline] 1104 pub fn iter_raw_parse_order_from( 1105 &self, 1106 offset: usize, 1107 ) -> Rev<slice::Iter<'_, Component<Impl>>> { 1108 self.0.slice()[..self.len() - offset].iter().rev() 1109 } 1110 1111 /// Creates a Selector from a vec of Components, specified in parse order. Used in tests. 1112 #[allow(dead_code)] 1113 pub(crate) fn from_vec( 1114 vec: Vec<Component<Impl>>, 1115 specificity: u32, 1116 flags: SelectorFlags, 1117 ) -> Self { 1118 let mut builder = SelectorBuilder::default(); 1119 for component in vec.into_iter() { 1120 if let Some(combinator) = component.as_combinator() { 1121 builder.push_combinator(combinator); 1122 } else { 1123 builder.push_simple_selector(component); 1124 } 1125 } 1126 let spec = SpecificityAndFlags { specificity, flags }; 1127 Selector(builder.build_with_specificity_and_flags(spec, ParseRelative::No)) 1128 } 1129 1130 #[inline] 1131 fn into_data(self) -> SelectorData<Impl> { 1132 self.0 1133 } 1134 1135 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self { 1136 let parent_specificity_and_flags = selector_list_specificity_and_flags( 1137 parent.slice().iter(), 1138 /* for_nesting_parent = */ true, 1139 ); 1140 1141 let mut specificity = Specificity::from(self.specificity()); 1142 let mut flags = self.flags() - SelectorFlags::HAS_PARENT; 1143 let forbidden_flags = SelectorFlags::forbidden_for_nesting(); 1144 1145 fn replace_parent_on_selector_list<Impl: SelectorImpl>( 1146 orig: &[Selector<Impl>], 1147 parent: &SelectorList<Impl>, 1148 specificity: &mut Specificity, 1149 flags: &mut SelectorFlags, 1150 propagate_specificity: bool, 1151 forbidden_flags: SelectorFlags, 1152 ) -> Option<SelectorList<Impl>> { 1153 if !orig.iter().any(|s| s.has_parent_selector()) { 1154 return None; 1155 } 1156 1157 let result = 1158 SelectorList::from_iter(orig.iter().map(|s| s.replace_parent_selector(parent))); 1159 1160 let result_specificity_and_flags = selector_list_specificity_and_flags( 1161 result.slice().iter(), 1162 /* for_nesting_parent = */ false, 1163 ); 1164 if propagate_specificity { 1165 *specificity += Specificity::from( 1166 result_specificity_and_flags.specificity 1167 - selector_list_specificity_and_flags( 1168 orig.iter(), 1169 /* for_nesting_parent = */ false, 1170 ) 1171 .specificity, 1172 ); 1173 } 1174 flags.insert(result_specificity_and_flags.flags - forbidden_flags); 1175 Some(result) 1176 } 1177 1178 fn replace_parent_on_relative_selector_list<Impl: SelectorImpl>( 1179 orig: &[RelativeSelector<Impl>], 1180 parent: &SelectorList<Impl>, 1181 specificity: &mut Specificity, 1182 flags: &mut SelectorFlags, 1183 forbidden_flags: SelectorFlags, 1184 ) -> Vec<RelativeSelector<Impl>> { 1185 let mut any = false; 1186 1187 let result = orig 1188 .iter() 1189 .map(|s| { 1190 if !s.selector.has_parent_selector() { 1191 return s.clone(); 1192 } 1193 any = true; 1194 RelativeSelector { 1195 match_hint: s.match_hint, 1196 selector: s.selector.replace_parent_selector(parent), 1197 } 1198 }) 1199 .collect(); 1200 1201 if !any { 1202 return result; 1203 } 1204 1205 let result_specificity_and_flags = relative_selector_list_specificity_and_flags( 1206 &result, /* for_nesting_parent = */ false, 1207 ); 1208 flags.insert(result_specificity_and_flags.flags - forbidden_flags); 1209 *specificity += Specificity::from( 1210 result_specificity_and_flags.specificity 1211 - relative_selector_list_specificity_and_flags( 1212 orig, /* for_nesting_parent = */ false, 1213 ) 1214 .specificity, 1215 ); 1216 result 1217 } 1218 1219 fn replace_parent_on_selector<Impl: SelectorImpl>( 1220 orig: &Selector<Impl>, 1221 parent: &SelectorList<Impl>, 1222 specificity: &mut Specificity, 1223 flags: &mut SelectorFlags, 1224 forbidden_flags: SelectorFlags, 1225 ) -> Selector<Impl> { 1226 let new_selector = orig.replace_parent_selector(parent); 1227 *specificity += Specificity::from(new_selector.specificity() - orig.specificity()); 1228 flags.insert(new_selector.flags() - forbidden_flags); 1229 new_selector 1230 } 1231 1232 if !self.has_parent_selector() { 1233 return self.clone(); 1234 } 1235 1236 let iter = self.iter_raw_match_order().map(|component| { 1237 use self::Component::*; 1238 match *component { 1239 LocalName(..) 1240 | ID(..) 1241 | Class(..) 1242 | AttributeInNoNamespaceExists { .. } 1243 | AttributeInNoNamespace { .. } 1244 | AttributeOther(..) 1245 | ExplicitUniversalType 1246 | ExplicitAnyNamespace 1247 | ExplicitNoNamespace 1248 | DefaultNamespace(..) 1249 | Namespace(..) 1250 | Root 1251 | Empty 1252 | Scope 1253 | ImplicitScope 1254 | Nth(..) 1255 | NonTSPseudoClass(..) 1256 | PseudoElement(..) 1257 | Combinator(..) 1258 | Host(None) 1259 | Part(..) 1260 | Invalid(..) 1261 | RelativeSelectorAnchor => component.clone(), 1262 ParentSelector => { 1263 specificity += Specificity::from(parent_specificity_and_flags.specificity); 1264 flags.insert(parent_specificity_and_flags.flags - forbidden_flags); 1265 Is(parent.clone()) 1266 }, 1267 Negation(ref selectors) => { 1268 Negation( 1269 replace_parent_on_selector_list( 1270 selectors.slice(), 1271 parent, 1272 &mut specificity, 1273 &mut flags, 1274 /* propagate_specificity = */ true, 1275 forbidden_flags, 1276 ) 1277 .unwrap_or_else(|| selectors.clone()), 1278 ) 1279 }, 1280 Is(ref selectors) => { 1281 Is(replace_parent_on_selector_list( 1282 selectors.slice(), 1283 parent, 1284 &mut specificity, 1285 &mut flags, 1286 /* propagate_specificity = */ true, 1287 forbidden_flags, 1288 ) 1289 .unwrap_or_else(|| selectors.clone())) 1290 }, 1291 Where(ref selectors) => { 1292 Where( 1293 replace_parent_on_selector_list( 1294 selectors.slice(), 1295 parent, 1296 &mut specificity, 1297 &mut flags, 1298 /* propagate_specificity = */ false, 1299 forbidden_flags, 1300 ) 1301 .unwrap_or_else(|| selectors.clone()), 1302 ) 1303 }, 1304 Has(ref selectors) => Has(replace_parent_on_relative_selector_list( 1305 selectors, 1306 parent, 1307 &mut specificity, 1308 &mut flags, 1309 forbidden_flags, 1310 ) 1311 .into_boxed_slice()), 1312 1313 Host(Some(ref selector)) => Host(Some(replace_parent_on_selector( 1314 selector, 1315 parent, 1316 &mut specificity, 1317 &mut flags, 1318 forbidden_flags, 1319 ))), 1320 NthOf(ref data) => { 1321 let selectors = replace_parent_on_selector_list( 1322 data.selectors(), 1323 parent, 1324 &mut specificity, 1325 &mut flags, 1326 /* propagate_specificity = */ true, 1327 forbidden_flags, 1328 ); 1329 NthOf(match selectors { 1330 Some(s) => { 1331 NthOfSelectorData::new(data.nth_data(), s.slice().iter().cloned()) 1332 }, 1333 None => data.clone(), 1334 }) 1335 }, 1336 Slotted(ref selector) => Slotted(replace_parent_on_selector( 1337 selector, 1338 parent, 1339 &mut specificity, 1340 &mut flags, 1341 forbidden_flags, 1342 )), 1343 } 1344 }); 1345 let mut items = UniqueArc::from_header_and_iter(Default::default(), iter); 1346 *items.header_mut() = SpecificityAndFlags { 1347 specificity: specificity.into(), 1348 flags, 1349 }; 1350 Selector(items.shareable()) 1351 } 1352 1353 /// Returns count of simple selectors and combinators in the Selector. 1354 #[inline] 1355 pub fn len(&self) -> usize { 1356 self.0.len() 1357 } 1358 1359 /// Returns the address on the heap of the ThinArc for memory reporting. 1360 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void { 1361 self.0.heap_ptr() 1362 } 1363 1364 /// Traverse selector components inside `self`. 1365 /// 1366 /// Implementations of this method should call `SelectorVisitor` methods 1367 /// or other impls of `Visit` as appropriate based on the fields of `Self`. 1368 /// 1369 /// A return value of `false` indicates terminating the traversal. 1370 /// It should be propagated with an early return. 1371 /// On the contrary, `true` indicates that all fields of `self` have been traversed: 1372 /// 1373 /// ```rust,ignore 1374 /// if !visitor.visit_simple_selector(&self.some_simple_selector) { 1375 /// return false; 1376 /// } 1377 /// if !self.some_component.visit(visitor) { 1378 /// return false; 1379 /// } 1380 /// true 1381 /// ``` 1382 pub fn visit<V>(&self, visitor: &mut V) -> bool 1383 where 1384 V: SelectorVisitor<Impl = Impl>, 1385 { 1386 let mut current = self.iter(); 1387 let mut combinator = None; 1388 loop { 1389 if !visitor.visit_complex_selector(combinator) { 1390 return false; 1391 } 1392 1393 for selector in &mut current { 1394 if !selector.visit(visitor) { 1395 return false; 1396 } 1397 } 1398 1399 combinator = current.next_sequence(); 1400 if combinator.is_none() { 1401 break; 1402 } 1403 } 1404 1405 true 1406 } 1407 1408 /// Parse a selector, without any pseudo-element. 1409 #[inline] 1410 pub fn parse<'i, 't, P>( 1411 parser: &P, 1412 input: &mut CssParser<'i, 't>, 1413 ) -> Result<Self, ParseError<'i, P::Error>> 1414 where 1415 P: Parser<'i, Impl = Impl>, 1416 { 1417 parse_selector( 1418 parser, 1419 input, 1420 SelectorParsingState::empty(), 1421 ParseRelative::No, 1422 ) 1423 } 1424 1425 pub fn new_invalid(s: &str) -> Self { 1426 fn check_for_parent(input: &mut CssParser, has_parent: &mut bool) { 1427 while let Ok(t) = input.next() { 1428 match *t { 1429 Token::Function(_) 1430 | Token::ParenthesisBlock 1431 | Token::CurlyBracketBlock 1432 | Token::SquareBracketBlock => { 1433 let _ = input.parse_nested_block( 1434 |i| -> Result<(), ParseError<'_, BasicParseError>> { 1435 check_for_parent(i, has_parent); 1436 Ok(()) 1437 }, 1438 ); 1439 }, 1440 Token::Delim('&') => { 1441 *has_parent = true; 1442 }, 1443 _ => {}, 1444 } 1445 if *has_parent { 1446 break; 1447 } 1448 } 1449 } 1450 let mut has_parent = false; 1451 { 1452 let mut parser = cssparser::ParserInput::new(s); 1453 let mut parser = CssParser::new(&mut parser); 1454 check_for_parent(&mut parser, &mut has_parent); 1455 } 1456 Self(ThinArc::from_header_and_iter( 1457 SpecificityAndFlags { 1458 specificity: 0, 1459 flags: if has_parent { 1460 SelectorFlags::HAS_PARENT 1461 } else { 1462 SelectorFlags::empty() 1463 }, 1464 }, 1465 std::iter::once(Component::Invalid(Arc::new(String::from(s.trim())))), 1466 )) 1467 } 1468 1469 /// Is the compound starting at the offset the subject compound, or referring to its pseudo-element? 1470 pub fn is_rightmost(&self, offset: usize) -> bool { 1471 // There can really be only one pseudo-element, and it's not really valid for anything else to 1472 // follow it. 1473 offset == 0 1474 || matches!( 1475 self.combinator_at_match_order(offset - 1), 1476 Combinator::PseudoElement 1477 ) 1478 } 1479 } 1480 1481 #[derive(Clone)] 1482 pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> { 1483 iter: slice::Iter<'a, Component<Impl>>, 1484 next_combinator: Option<Combinator>, 1485 } 1486 1487 impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> { 1488 /// Prepares this iterator to point to the next sequence to the left, 1489 /// returning the combinator if the sequence was found. 1490 #[inline] 1491 pub fn next_sequence(&mut self) -> Option<Combinator> { 1492 self.next_combinator.take() 1493 } 1494 1495 #[inline] 1496 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool { 1497 let first = match self.next() { 1498 Some(c) => c, 1499 // Note that this is the common path that we keep inline: the 1500 // pseudo-element not having anything to its right. 1501 None => return true, 1502 }; 1503 self.matches_for_stateless_pseudo_element_internal(first) 1504 } 1505 1506 #[inline(never)] 1507 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool { 1508 if !first.matches_for_stateless_pseudo_element() { 1509 return false; 1510 } 1511 for component in self { 1512 // The only other parser-allowed Components in this sequence are 1513 // state pseudo-classes, or one of the other things that can contain 1514 // them. 1515 if !component.matches_for_stateless_pseudo_element() { 1516 return false; 1517 } 1518 } 1519 true 1520 } 1521 1522 /// Returns remaining count of the simple selectors and combinators in the Selector. 1523 #[inline] 1524 pub fn selector_length(&self) -> usize { 1525 self.iter.len() 1526 } 1527 } 1528 1529 impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> { 1530 type Item = &'a Component<Impl>; 1531 1532 #[inline] 1533 fn next(&mut self) -> Option<Self::Item> { 1534 debug_assert!( 1535 self.next_combinator.is_none(), 1536 "You should call next_sequence!" 1537 ); 1538 match *self.iter.next()? { 1539 Component::Combinator(c) => { 1540 self.next_combinator = Some(c); 1541 None 1542 }, 1543 ref x => Some(x), 1544 } 1545 } 1546 } 1547 1548 impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> { 1549 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1550 let iter = self.iter.clone().rev(); 1551 for component in iter { 1552 component.to_css(f)? 1553 } 1554 Ok(()) 1555 } 1556 } 1557 1558 /// An iterator over all combinators in a selector. Does not traverse selectors within psuedoclasses. 1559 struct CombinatorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>); 1560 impl<'a, Impl: 'a + SelectorImpl> CombinatorIter<'a, Impl> { 1561 fn new(inner: SelectorIter<'a, Impl>) -> Self { 1562 let mut result = CombinatorIter(inner); 1563 result.consume_non_combinators(); 1564 result 1565 } 1566 1567 fn consume_non_combinators(&mut self) { 1568 while self.0.next().is_some() {} 1569 } 1570 } 1571 1572 impl<'a, Impl: SelectorImpl> Iterator for CombinatorIter<'a, Impl> { 1573 type Item = Combinator; 1574 fn next(&mut self) -> Option<Self::Item> { 1575 let result = self.0.next_sequence(); 1576 self.consume_non_combinators(); 1577 result 1578 } 1579 } 1580 1581 /// An iterator over all simple selectors belonging to ancestors. 1582 struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>); 1583 impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> { 1584 /// Creates an AncestorIter. The passed-in iterator is assumed to point to 1585 /// the beginning of the child sequence, which will be skipped. 1586 fn new(inner: SelectorIter<'a, Impl>) -> Self { 1587 let mut result = AncestorIter(inner); 1588 result.skip_until_ancestor(); 1589 result 1590 } 1591 1592 /// Skips a sequence of simple selectors and all subsequent sequences until 1593 /// a non-pseudo-element ancestor combinator is reached. 1594 fn skip_until_ancestor(&mut self) { 1595 loop { 1596 while self.0.next().is_some() {} 1597 // If this is ever changed to stop at the "pseudo-element" 1598 // combinator, we will need to fix the way we compute hashes for 1599 // revalidation selectors. 1600 if self.0.next_sequence().map_or(true, |x| { 1601 matches!(x, Combinator::Child | Combinator::Descendant) 1602 }) { 1603 break; 1604 } 1605 } 1606 } 1607 } 1608 1609 impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> { 1610 type Item = &'a Component<Impl>; 1611 fn next(&mut self) -> Option<Self::Item> { 1612 // Grab the next simple selector in the sequence if available. 1613 let next = self.0.next(); 1614 if next.is_some() { 1615 return next; 1616 } 1617 1618 // See if there are more sequences. If so, skip any non-ancestor sequences. 1619 if let Some(combinator) = self.0.next_sequence() { 1620 if !matches!(combinator, Combinator::Child | Combinator::Descendant) { 1621 self.skip_until_ancestor(); 1622 } 1623 } 1624 1625 self.0.next() 1626 } 1627 } 1628 1629 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 1630 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 1631 pub enum Combinator { 1632 Child, // > 1633 Descendant, // space 1634 NextSibling, // + 1635 LaterSibling, // ~ 1636 /// A dummy combinator we use to the left of pseudo-elements. 1637 /// 1638 /// It serializes as the empty string, and acts effectively as a child 1639 /// combinator in most cases. If we ever actually start using a child 1640 /// combinator for this, we will need to fix up the way hashes are computed 1641 /// for revalidation selectors. 1642 PseudoElement, 1643 /// Another combinator used for ::slotted(), which represent the jump from 1644 /// a node to its assigned slot. 1645 SlotAssignment, 1646 /// Another combinator used for `::part()`, which represents the jump from 1647 /// the part to the containing shadow host. 1648 Part, 1649 } 1650 1651 impl Combinator { 1652 /// Returns true if this combinator is a child or descendant combinator. 1653 #[inline] 1654 pub fn is_ancestor(&self) -> bool { 1655 matches!( 1656 *self, 1657 Combinator::Child 1658 | Combinator::Descendant 1659 | Combinator::PseudoElement 1660 | Combinator::SlotAssignment 1661 ) 1662 } 1663 1664 /// Returns true if this combinator is a pseudo-element combinator. 1665 #[inline] 1666 pub fn is_pseudo_element(&self) -> bool { 1667 matches!(*self, Combinator::PseudoElement) 1668 } 1669 1670 /// Returns true if this combinator is a next- or later-sibling combinator. 1671 #[inline] 1672 pub fn is_sibling(&self) -> bool { 1673 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling) 1674 } 1675 } 1676 1677 /// An enum for the different types of :nth- pseudoclasses 1678 #[derive(Copy, Clone, Eq, PartialEq)] 1679 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 1680 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 1681 pub enum NthType { 1682 Child, 1683 LastChild, 1684 OnlyChild, 1685 OfType, 1686 LastOfType, 1687 OnlyOfType, 1688 } 1689 1690 impl NthType { 1691 pub fn is_only(self) -> bool { 1692 self == Self::OnlyChild || self == Self::OnlyOfType 1693 } 1694 1695 pub fn is_of_type(self) -> bool { 1696 self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType 1697 } 1698 1699 pub fn is_from_end(self) -> bool { 1700 self == Self::LastChild || self == Self::LastOfType 1701 } 1702 } 1703 1704 /// The properties that comprise an An+B syntax 1705 #[derive(Copy, Clone, Eq, PartialEq, Debug)] 1706 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 1707 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 1708 pub struct AnPlusB(pub i32, pub i32); 1709 1710 impl AnPlusB { 1711 #[inline] 1712 pub fn matches_index(&self, i: i32) -> bool { 1713 // Is there a non-negative integer n such that An+B=i? 1714 match i.checked_sub(self.1) { 1715 None => false, 1716 Some(an) => match an.checked_div(self.0) { 1717 Some(n) => n >= 0 && self.0 * n == an, 1718 None /* a == 0 */ => an == 0, 1719 }, 1720 } 1721 } 1722 } 1723 1724 impl ToCss for AnPlusB { 1725 /// Serialize <an+b> (part of the CSS Syntax spec). 1726 /// <https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value> 1727 #[inline] 1728 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 1729 where 1730 W: fmt::Write, 1731 { 1732 match (self.0, self.1) { 1733 (0, 0) => dest.write_char('0'), 1734 1735 (1, 0) => dest.write_char('n'), 1736 (-1, 0) => dest.write_str("-n"), 1737 (_, 0) => write!(dest, "{}n", self.0), 1738 1739 (0, _) => write!(dest, "{}", self.1), 1740 (1, _) => write!(dest, "n{:+}", self.1), 1741 (-1, _) => write!(dest, "-n{:+}", self.1), 1742 (_, _) => write!(dest, "{}n{:+}", self.0, self.1), 1743 } 1744 } 1745 } 1746 1747 /// The properties that comprise an :nth- pseudoclass as of Selectors 3 (e.g., 1748 /// nth-child(An+B)). 1749 /// https://www.w3.org/TR/selectors-3/#nth-child-pseudo 1750 #[derive(Copy, Clone, Eq, PartialEq)] 1751 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 1752 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 1753 pub struct NthSelectorData { 1754 pub ty: NthType, 1755 pub is_function: bool, 1756 pub an_plus_b: AnPlusB, 1757 } 1758 1759 impl NthSelectorData { 1760 /// Returns selector data for :only-{child,of-type} 1761 #[inline] 1762 pub const fn only(of_type: bool) -> Self { 1763 Self { 1764 ty: if of_type { 1765 NthType::OnlyOfType 1766 } else { 1767 NthType::OnlyChild 1768 }, 1769 is_function: false, 1770 an_plus_b: AnPlusB(0, 1), 1771 } 1772 } 1773 1774 /// Returns selector data for :first-{child,of-type} 1775 #[inline] 1776 pub const fn first(of_type: bool) -> Self { 1777 Self { 1778 ty: if of_type { 1779 NthType::OfType 1780 } else { 1781 NthType::Child 1782 }, 1783 is_function: false, 1784 an_plus_b: AnPlusB(0, 1), 1785 } 1786 } 1787 1788 /// Returns selector data for :last-{child,of-type} 1789 #[inline] 1790 pub const fn last(of_type: bool) -> Self { 1791 Self { 1792 ty: if of_type { 1793 NthType::LastOfType 1794 } else { 1795 NthType::LastChild 1796 }, 1797 is_function: false, 1798 an_plus_b: AnPlusB(0, 1), 1799 } 1800 } 1801 1802 /// Returns true if this is an edge selector that is not `:*-of-type`` 1803 #[inline] 1804 pub fn is_simple_edge(&self) -> bool { 1805 self.an_plus_b.0 == 0 1806 && self.an_plus_b.1 == 1 1807 && !self.ty.is_of_type() 1808 && !self.ty.is_only() 1809 } 1810 1811 /// Writes the beginning of the selector. 1812 #[inline] 1813 fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result { 1814 dest.write_str(match self.ty { 1815 NthType::Child if self.is_function => ":nth-child(", 1816 NthType::Child => ":first-child", 1817 NthType::LastChild if self.is_function => ":nth-last-child(", 1818 NthType::LastChild => ":last-child", 1819 NthType::OfType if self.is_function => ":nth-of-type(", 1820 NthType::OfType => ":first-of-type", 1821 NthType::LastOfType if self.is_function => ":nth-last-of-type(", 1822 NthType::LastOfType => ":last-of-type", 1823 NthType::OnlyChild => ":only-child", 1824 NthType::OnlyOfType => ":only-of-type", 1825 }) 1826 } 1827 1828 #[inline] 1829 fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result { 1830 self.an_plus_b.to_css(dest) 1831 } 1832 } 1833 1834 /// The properties that comprise an :nth- pseudoclass as of Selectors 4 (e.g., 1835 /// nth-child(An+B [of S]?)). 1836 /// https://www.w3.org/TR/selectors-4/#nth-child-pseudo 1837 #[derive(Clone, Eq, PartialEq)] 1838 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 1839 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 1840 pub struct NthOfSelectorData<Impl: SelectorImpl>( 1841 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] ThinArc<NthSelectorData, Selector<Impl>>, 1842 ); 1843 1844 impl<Impl: SelectorImpl> NthOfSelectorData<Impl> { 1845 /// Returns selector data for :nth-{,last-}{child,of-type}(An+B [of S]) 1846 #[inline] 1847 pub fn new<I>(nth_data: &NthSelectorData, selectors: I) -> Self 1848 where 1849 I: Iterator<Item = Selector<Impl>> + ExactSizeIterator, 1850 { 1851 Self(ThinArc::from_header_and_iter(*nth_data, selectors)) 1852 } 1853 1854 /// Returns the An+B part of the selector 1855 #[inline] 1856 pub fn nth_data(&self) -> &NthSelectorData { 1857 &self.0.header 1858 } 1859 1860 /// Returns the selector list part of the selector 1861 #[inline] 1862 pub fn selectors(&self) -> &[Selector<Impl>] { 1863 self.0.slice() 1864 } 1865 } 1866 1867 /// Flag indicating where a given relative selector's match would be contained. 1868 #[derive(Clone, Copy, Eq, PartialEq)] 1869 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 1870 pub enum RelativeSelectorMatchHint { 1871 /// Within this element's subtree. 1872 InSubtree, 1873 /// Within this element's direct children. 1874 InChild, 1875 /// This element's next sibling. 1876 InNextSibling, 1877 /// Within this element's next sibling's subtree. 1878 InNextSiblingSubtree, 1879 /// Within this element's subsequent siblings. 1880 InSibling, 1881 /// Across this element's subsequent siblings and their subtrees. 1882 InSiblingSubtree, 1883 } 1884 1885 impl RelativeSelectorMatchHint { 1886 /// Create a new relative selector match hint based on its composition. 1887 pub fn new( 1888 relative_combinator: Combinator, 1889 has_child_or_descendants: bool, 1890 has_adjacent_or_next_siblings: bool, 1891 ) -> Self { 1892 match relative_combinator { 1893 Combinator::Descendant => RelativeSelectorMatchHint::InSubtree, 1894 Combinator::Child => { 1895 if !has_child_or_descendants { 1896 RelativeSelectorMatchHint::InChild 1897 } else { 1898 // Technically, for any composition that consists of child combinators only, 1899 // the search space is depth-constrained, but it's probably not worth optimizing for. 1900 RelativeSelectorMatchHint::InSubtree 1901 } 1902 }, 1903 Combinator::NextSibling => { 1904 if !has_child_or_descendants && !has_adjacent_or_next_siblings { 1905 RelativeSelectorMatchHint::InNextSibling 1906 } else if !has_child_or_descendants && has_adjacent_or_next_siblings { 1907 RelativeSelectorMatchHint::InSibling 1908 } else if has_child_or_descendants && !has_adjacent_or_next_siblings { 1909 // Match won't cross multiple siblings. 1910 RelativeSelectorMatchHint::InNextSiblingSubtree 1911 } else { 1912 RelativeSelectorMatchHint::InSiblingSubtree 1913 } 1914 }, 1915 Combinator::LaterSibling => { 1916 if !has_child_or_descendants { 1917 RelativeSelectorMatchHint::InSibling 1918 } else { 1919 // Even if the match may not cross multiple siblings, we have to look until 1920 // we find a match anyway. 1921 RelativeSelectorMatchHint::InSiblingSubtree 1922 } 1923 }, 1924 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => { 1925 debug_assert!(false, "Unexpected relative combinator"); 1926 RelativeSelectorMatchHint::InSubtree 1927 }, 1928 } 1929 } 1930 1931 /// Is the match traversal direction towards the descendant of this element (As opposed to siblings)? 1932 pub fn is_descendant_direction(&self) -> bool { 1933 matches!(*self, Self::InChild | Self::InSubtree) 1934 } 1935 1936 /// Is the match traversal terminated at the next sibling? 1937 pub fn is_next_sibling(&self) -> bool { 1938 matches!(*self, Self::InNextSibling | Self::InNextSiblingSubtree) 1939 } 1940 1941 /// Does the match involve matching the subtree? 1942 pub fn is_subtree(&self) -> bool { 1943 matches!( 1944 *self, 1945 Self::InSubtree | Self::InSiblingSubtree | Self::InNextSiblingSubtree 1946 ) 1947 } 1948 } 1949 1950 /// Count of combinators in a given relative selector, not traversing selectors of pseudoclasses. 1951 #[derive(Clone, Copy)] 1952 pub struct RelativeSelectorCombinatorCount { 1953 relative_combinator: Combinator, 1954 pub child_or_descendants: usize, 1955 pub adjacent_or_next_siblings: usize, 1956 } 1957 1958 impl RelativeSelectorCombinatorCount { 1959 /// Create a new relative selector combinator count from a given relative selector. 1960 pub fn new<Impl: SelectorImpl>(relative_selector: &RelativeSelector<Impl>) -> Self { 1961 let mut result = RelativeSelectorCombinatorCount { 1962 relative_combinator: relative_selector.selector.combinator_at_parse_order(1), 1963 child_or_descendants: 0, 1964 adjacent_or_next_siblings: 0, 1965 }; 1966 1967 for combinator in CombinatorIter::new( 1968 relative_selector 1969 .selector 1970 .iter_skip_relative_selector_anchor(), 1971 ) { 1972 match combinator { 1973 Combinator::Descendant | Combinator::Child => { 1974 result.child_or_descendants += 1; 1975 }, 1976 Combinator::NextSibling | Combinator::LaterSibling => { 1977 result.adjacent_or_next_siblings += 1; 1978 }, 1979 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => { 1980 continue 1981 }, 1982 }; 1983 } 1984 result 1985 } 1986 1987 /// Get the match hint based on the current combinator count. 1988 pub fn get_match_hint(&self) -> RelativeSelectorMatchHint { 1989 RelativeSelectorMatchHint::new( 1990 self.relative_combinator, 1991 self.child_or_descendants != 0, 1992 self.adjacent_or_next_siblings != 0, 1993 ) 1994 } 1995 } 1996 1997 /// Storage for a relative selector. 1998 #[derive(Clone, Eq, PartialEq)] 1999 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 2000 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 2001 pub struct RelativeSelector<Impl: SelectorImpl> { 2002 /// Match space constraining hint. 2003 pub match_hint: RelativeSelectorMatchHint, 2004 /// The selector. Guaranteed to contain `RelativeSelectorAnchor` and the relative combinator in parse order. 2005 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] 2006 pub selector: Selector<Impl>, 2007 } 2008 2009 bitflags! { 2010 /// Composition of combinators in a given selector, not traversing selectors of pseudoclasses. 2011 #[derive(Clone, Debug, Eq, PartialEq)] 2012 struct CombinatorComposition: u8 { 2013 const DESCENDANTS = 1 << 0; 2014 const SIBLINGS = 1 << 1; 2015 } 2016 } 2017 2018 impl CombinatorComposition { 2019 fn for_relative_selector<Impl: SelectorImpl>(inner_selector: &Selector<Impl>) -> Self { 2020 let mut result = CombinatorComposition::empty(); 2021 for combinator in CombinatorIter::new(inner_selector.iter_skip_relative_selector_anchor()) { 2022 match combinator { 2023 Combinator::Descendant | Combinator::Child => { 2024 result.insert(Self::DESCENDANTS); 2025 }, 2026 Combinator::NextSibling | Combinator::LaterSibling => { 2027 result.insert(Self::SIBLINGS); 2028 }, 2029 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => { 2030 continue 2031 }, 2032 }; 2033 if result.is_all() { 2034 break; 2035 } 2036 } 2037 return result; 2038 } 2039 } 2040 2041 impl<Impl: SelectorImpl> RelativeSelector<Impl> { 2042 fn from_selector_list(selector_list: SelectorList<Impl>) -> Box<[Self]> { 2043 selector_list 2044 .slice() 2045 .iter() 2046 .map(|selector| { 2047 // It's more efficient to keep track of all this during the parse time, but that seems like a lot of special 2048 // case handling for what it's worth. 2049 if cfg!(debug_assertions) { 2050 let relative_selector_anchor = selector.iter_raw_parse_order_from(0).next(); 2051 debug_assert!( 2052 relative_selector_anchor.is_some(), 2053 "Relative selector is empty" 2054 ); 2055 debug_assert!( 2056 matches!( 2057 relative_selector_anchor.unwrap(), 2058 Component::RelativeSelectorAnchor 2059 ), 2060 "Relative selector anchor is missing" 2061 ); 2062 } 2063 // Leave a hint for narrowing down the search space when we're matching. 2064 let composition = CombinatorComposition::for_relative_selector(&selector); 2065 let match_hint = RelativeSelectorMatchHint::new( 2066 selector.combinator_at_parse_order(1), 2067 composition.intersects(CombinatorComposition::DESCENDANTS), 2068 composition.intersects(CombinatorComposition::SIBLINGS), 2069 ); 2070 RelativeSelector { 2071 match_hint, 2072 selector: selector.clone(), 2073 } 2074 }) 2075 .collect() 2076 } 2077 } 2078 2079 /// A CSS simple selector or combinator. We store both in the same enum for 2080 /// optimal packing and cache performance, see [1]. 2081 /// 2082 /// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1357973 2083 #[derive(Clone, Eq, PartialEq)] 2084 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 2085 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 2086 pub enum Component<Impl: SelectorImpl> { 2087 LocalName(LocalName<Impl>), 2088 2089 ID(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier), 2090 Class(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier), 2091 2092 AttributeInNoNamespaceExists { 2093 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] 2094 local_name: Impl::LocalName, 2095 local_name_lower: Impl::LocalName, 2096 }, 2097 // Used only when local_name is already lowercase. 2098 AttributeInNoNamespace { 2099 local_name: Impl::LocalName, 2100 operator: AttrSelectorOperator, 2101 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] 2102 value: Impl::AttrValue, 2103 case_sensitivity: ParsedCaseSensitivity, 2104 }, 2105 // Use a Box in the less common cases with more data to keep size_of::<Component>() small. 2106 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>), 2107 2108 ExplicitUniversalType, 2109 ExplicitAnyNamespace, 2110 2111 ExplicitNoNamespace, 2112 DefaultNamespace(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl), 2113 Namespace( 2114 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespacePrefix, 2115 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl, 2116 ), 2117 2118 /// Pseudo-classes 2119 Negation(SelectorList<Impl>), 2120 Root, 2121 Empty, 2122 Scope, 2123 /// :scope added implicitly into scoped rules (i.e. In `@scope`) not 2124 /// explicitly using `:scope` or `&` selectors. 2125 /// 2126 /// https://drafts.csswg.org/css-cascade-6/#scoped-rules 2127 /// 2128 /// Unlike the normal `:scope` selector, this does not add any specificity. 2129 /// See https://github.com/w3c/csswg-drafts/issues/10196 2130 ImplicitScope, 2131 ParentSelector, 2132 Nth(NthSelectorData), 2133 NthOf(NthOfSelectorData<Impl>), 2134 NonTSPseudoClass(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NonTSPseudoClass), 2135 /// The ::slotted() pseudo-element: 2136 /// 2137 /// https://drafts.csswg.org/css-scoping/#slotted-pseudo 2138 /// 2139 /// The selector here is a compound selector, that is, no combinators. 2140 /// 2141 /// NOTE(emilio): This should support a list of selectors, but as of this 2142 /// writing no other browser does, and that allows them to put ::slotted() 2143 /// in the rule hash, so we do that too. 2144 /// 2145 /// See https://github.com/w3c/csswg-drafts/issues/2158 2146 Slotted(Selector<Impl>), 2147 /// The `::part` pseudo-element. 2148 /// https://drafts.csswg.org/css-shadow-parts/#part 2149 Part(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Box<[Impl::Identifier]>), 2150 /// The `:host` pseudo-class: 2151 /// 2152 /// https://drafts.csswg.org/css-scoping/#host-selector 2153 /// 2154 /// NOTE(emilio): This should support a list of selectors, but as of this 2155 /// writing no other browser does, and that allows them to put :host() 2156 /// in the rule hash, so we do that too. 2157 /// 2158 /// See https://github.com/w3c/csswg-drafts/issues/2158 2159 Host(Option<Selector<Impl>>), 2160 /// The `:where` pseudo-class. 2161 /// 2162 /// https://drafts.csswg.org/selectors/#zero-matches 2163 /// 2164 /// The inner argument is conceptually a SelectorList, but we move the 2165 /// selectors to the heap to keep Component small. 2166 Where(SelectorList<Impl>), 2167 /// The `:is` pseudo-class. 2168 /// 2169 /// https://drafts.csswg.org/selectors/#matches-pseudo 2170 /// 2171 /// Same comment as above re. the argument. 2172 Is(SelectorList<Impl>), 2173 /// The `:has` pseudo-class. 2174 /// 2175 /// https://drafts.csswg.org/selectors/#has-pseudo 2176 /// 2177 /// Same comment as above re. the argument. 2178 Has(Box<[RelativeSelector<Impl>]>), 2179 /// An invalid selector inside :is() / :where(). 2180 Invalid(Arc<String>), 2181 /// An implementation-dependent pseudo-element selector. 2182 PseudoElement(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::PseudoElement), 2183 2184 Combinator(Combinator), 2185 2186 /// Used only for relative selectors, which starts with a combinator 2187 /// (With an implied descendant combinator if not specified). 2188 /// 2189 /// https://drafts.csswg.org/selectors-4/#typedef-relative-selector 2190 RelativeSelectorAnchor, 2191 } 2192 2193 impl<Impl: SelectorImpl> Component<Impl> { 2194 /// Returns true if this is a combinator. 2195 #[inline] 2196 pub fn is_combinator(&self) -> bool { 2197 matches!(*self, Component::Combinator(_)) 2198 } 2199 2200 /// Returns true if this is a :host() selector. 2201 #[inline] 2202 pub fn is_host(&self) -> bool { 2203 matches!(*self, Component::Host(..)) 2204 } 2205 2206 /// Returns the value as a combinator if applicable, None otherwise. 2207 pub fn as_combinator(&self) -> Option<Combinator> { 2208 match *self { 2209 Component::Combinator(c) => Some(c), 2210 _ => None, 2211 } 2212 } 2213 2214 /// Whether a given selector (to the right of a pseudo-element) should match for stateless 2215 /// pseudo-elements. Note that generally nothing matches for those, but since we have :not(), 2216 /// we still need to traverse nested selector lists. 2217 fn matches_for_stateless_pseudo_element(&self) -> bool { 2218 match *self { 2219 Component::Negation(ref selectors) => !selectors.slice().iter().all(|selector| { 2220 selector 2221 .iter_raw_match_order() 2222 .all(|c| c.matches_for_stateless_pseudo_element()) 2223 }), 2224 Component::Is(ref selectors) | Component::Where(ref selectors) => { 2225 selectors.slice().iter().any(|selector| { 2226 selector 2227 .iter_raw_match_order() 2228 .all(|c| c.matches_for_stateless_pseudo_element()) 2229 }) 2230 }, 2231 _ => false, 2232 } 2233 } 2234 2235 pub fn visit<V>(&self, visitor: &mut V) -> bool 2236 where 2237 V: SelectorVisitor<Impl = Impl>, 2238 { 2239 use self::Component::*; 2240 if !visitor.visit_simple_selector(self) { 2241 return false; 2242 } 2243 2244 match *self { 2245 Slotted(ref selector) => { 2246 if !selector.visit(visitor) { 2247 return false; 2248 } 2249 }, 2250 Host(Some(ref selector)) => { 2251 if !selector.visit(visitor) { 2252 return false; 2253 } 2254 }, 2255 AttributeInNoNamespaceExists { 2256 ref local_name, 2257 ref local_name_lower, 2258 } => { 2259 if !visitor.visit_attribute_selector( 2260 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()), 2261 local_name, 2262 local_name_lower, 2263 ) { 2264 return false; 2265 } 2266 }, 2267 AttributeInNoNamespace { ref local_name, .. } => { 2268 if !visitor.visit_attribute_selector( 2269 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()), 2270 local_name, 2271 local_name, 2272 ) { 2273 return false; 2274 } 2275 }, 2276 AttributeOther(ref attr_selector) => { 2277 let empty_string; 2278 let namespace = match attr_selector.namespace() { 2279 Some(ns) => ns, 2280 None => { 2281 empty_string = crate::parser::namespace_empty_string::<Impl>(); 2282 NamespaceConstraint::Specific(&empty_string) 2283 }, 2284 }; 2285 if !visitor.visit_attribute_selector( 2286 &namespace, 2287 &attr_selector.local_name, 2288 &attr_selector.local_name_lower, 2289 ) { 2290 return false; 2291 } 2292 }, 2293 2294 NonTSPseudoClass(ref pseudo_class) => { 2295 if !pseudo_class.visit(visitor) { 2296 return false; 2297 } 2298 }, 2299 Negation(ref list) | Is(ref list) | Where(ref list) => { 2300 let list_kind = SelectorListKind::from_component(self); 2301 debug_assert!(!list_kind.is_empty()); 2302 if !visitor.visit_selector_list(list_kind, list.slice()) { 2303 return false; 2304 } 2305 }, 2306 NthOf(ref nth_of_data) => { 2307 if !visitor.visit_selector_list(SelectorListKind::NTH_OF, nth_of_data.selectors()) { 2308 return false; 2309 } 2310 }, 2311 Has(ref list) => { 2312 if !visitor.visit_relative_selector_list(list) { 2313 return false; 2314 } 2315 }, 2316 _ => {}, 2317 } 2318 2319 true 2320 } 2321 2322 // Returns true if this has any selector that requires an index calculation. e.g. 2323 // :nth-child, :first-child, etc. For nested selectors, return true only if the 2324 // indexed selector is in its subject compound. 2325 pub fn has_indexed_selector_in_subject(&self) -> bool { 2326 match *self { 2327 Component::NthOf(..) | Component::Nth(..) => return true, 2328 Component::Is(ref selectors) 2329 | Component::Where(ref selectors) 2330 | Component::Negation(ref selectors) => { 2331 // Check the subject compound. 2332 for selector in selectors.slice() { 2333 let mut iter = selector.iter(); 2334 while let Some(c) = iter.next() { 2335 if c.has_indexed_selector_in_subject() { 2336 return true; 2337 } 2338 } 2339 } 2340 }, 2341 _ => (), 2342 }; 2343 false 2344 } 2345 } 2346 2347 #[derive(Clone, Eq, PartialEq)] 2348 #[cfg_attr(feature = "to_shmem", derive(ToShmem))] 2349 #[cfg_attr(feature = "to_shmem", shmem(no_bounds))] 2350 pub struct LocalName<Impl: SelectorImpl> { 2351 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] 2352 pub name: Impl::LocalName, 2353 pub lower_name: Impl::LocalName, 2354 } 2355 2356 impl<Impl: SelectorImpl> Debug for Selector<Impl> { 2357 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 2358 f.write_str("Selector(")?; 2359 self.to_css(f)?; 2360 write!( 2361 f, 2362 ", specificity = {:#x}, flags = {:?})", 2363 self.specificity(), 2364 self.flags() 2365 ) 2366 } 2367 } 2368 2369 impl<Impl: SelectorImpl> Debug for Component<Impl> { 2370 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 2371 self.to_css(f) 2372 } 2373 } 2374 impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> { 2375 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 2376 self.to_css(f) 2377 } 2378 } 2379 impl<Impl: SelectorImpl> Debug for LocalName<Impl> { 2380 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 2381 self.to_css(f) 2382 } 2383 } 2384 2385 fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result 2386 where 2387 Impl: SelectorImpl, 2388 I: Iterator<Item = &'a Selector<Impl>>, 2389 W: fmt::Write, 2390 { 2391 let mut first = true; 2392 for selector in iter { 2393 if !first { 2394 dest.write_str(", ")?; 2395 } 2396 first = false; 2397 selector.to_css(dest)?; 2398 } 2399 Ok(()) 2400 } 2401 2402 impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> { 2403 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 2404 where 2405 W: fmt::Write, 2406 { 2407 serialize_selector_list(self.slice().iter(), dest) 2408 } 2409 } 2410 2411 impl<Impl: SelectorImpl> ToCss for Selector<Impl> { 2412 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 2413 where 2414 W: fmt::Write, 2415 { 2416 // Compound selectors invert the order of their contents, so we need to 2417 // undo that during serialization. 2418 // 2419 // This two-iterator strategy involves walking over the selector twice. 2420 // We could do something more clever, but selector serialization probably 2421 // isn't hot enough to justify it, and the stringification likely 2422 // dominates anyway. 2423 // 2424 // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(), 2425 // which we need for |split|. So we split by combinators on a match-order 2426 // sequence and then reverse. 2427 2428 let mut combinators = self 2429 .iter_raw_match_order() 2430 .rev() 2431 .filter_map(|x| x.as_combinator()); 2432 let compound_selectors = self 2433 .iter_raw_match_order() 2434 .as_slice() 2435 .split(|x| x.is_combinator()) 2436 .rev(); 2437 2438 let mut combinators_exhausted = false; 2439 for compound in compound_selectors { 2440 debug_assert!(!combinators_exhausted); 2441 2442 // https://drafts.csswg.org/cssom/#serializing-selectors 2443 let first_compound = match compound.first() { 2444 None => continue, 2445 Some(c) => c, 2446 }; 2447 if matches!( 2448 first_compound, 2449 Component::RelativeSelectorAnchor | Component::ImplicitScope 2450 ) { 2451 debug_assert!( 2452 compound.len() == 1, 2453 "RelativeSelectorAnchor/ImplicitScope should only be a simple selector" 2454 ); 2455 if let Some(c) = combinators.next() { 2456 c.to_css_relative(dest)?; 2457 } else { 2458 // Direct property declarations in `@scope` does not have 2459 // combinators, since its selector is `:implicit-scope`. 2460 debug_assert!( 2461 matches!(first_compound, Component::ImplicitScope), 2462 "Only implicit :scope may not have any combinator" 2463 ); 2464 } 2465 continue; 2466 } 2467 2468 // 1. If there is only one simple selector in the compound selectors 2469 // which is a universal selector, append the result of 2470 // serializing the universal selector to s. 2471 // 2472 // Check if `!compound.empty()` first--this can happen if we have 2473 // something like `... > ::before`, because we store `>` and `::` 2474 // both as combinators internally. 2475 // 2476 // If we are in this case, after we have serialized the universal 2477 // selector, we skip Step 2 and continue with the algorithm. 2478 let (can_elide_namespace, first_non_namespace) = match compound[0] { 2479 Component::ExplicitAnyNamespace 2480 | Component::ExplicitNoNamespace 2481 | Component::Namespace(..) => (false, 1), 2482 Component::DefaultNamespace(..) => (true, 1), 2483 _ => (true, 0), 2484 }; 2485 let mut perform_step_2 = true; 2486 let next_combinator = combinators.next(); 2487 if first_non_namespace == compound.len() - 1 { 2488 match (next_combinator, &compound[first_non_namespace]) { 2489 // We have to be careful here, because if there is a 2490 // pseudo element "combinator" there isn't really just 2491 // the one simple selector. Technically this compound 2492 // selector contains the pseudo element selector as well 2493 // -- Combinator::PseudoElement, just like 2494 // Combinator::SlotAssignment, don't exist in the 2495 // spec. 2496 (Some(Combinator::PseudoElement), _) 2497 | (Some(Combinator::SlotAssignment), _) => (), 2498 (_, &Component::ExplicitUniversalType) => { 2499 // Iterate over everything so we serialize the namespace 2500 // too. 2501 for simple in compound.iter() { 2502 simple.to_css(dest)?; 2503 } 2504 // Skip step 2, which is an "otherwise". 2505 perform_step_2 = false; 2506 }, 2507 _ => (), 2508 } 2509 } 2510 2511 // 2. Otherwise, for each simple selector in the compound selectors 2512 // that is not a universal selector of which the namespace prefix 2513 // maps to a namespace that is not the default namespace 2514 // serialize the simple selector and append the result to s. 2515 // 2516 // See https://github.com/w3c/csswg-drafts/issues/1606, which is 2517 // proposing to change this to match up with the behavior asserted 2518 // in cssom/serialize-namespaced-type-selectors.html, which the 2519 // following code tries to match. 2520 if perform_step_2 { 2521 for simple in compound.iter() { 2522 if let Component::ExplicitUniversalType = *simple { 2523 // Can't have a namespace followed by a pseudo-element 2524 // selector followed by a universal selector in the same 2525 // compound selector, so we don't have to worry about the 2526 // real namespace being in a different `compound`. 2527 if can_elide_namespace { 2528 continue; 2529 } 2530 } 2531 simple.to_css(dest)?; 2532 } 2533 } 2534 2535 // 3. If this is not the last part of the chain of the selector 2536 // append a single SPACE (U+0020), followed by the combinator 2537 // ">", "+", "~", ">>", "||", as appropriate, followed by another 2538 // single SPACE (U+0020) if the combinator was not whitespace, to 2539 // s. 2540 match next_combinator { 2541 Some(c) => c.to_css(dest)?, 2542 None => combinators_exhausted = true, 2543 }; 2544 2545 // 4. If this is the last part of the chain of the selector and 2546 // there is a pseudo-element, append "::" followed by the name of 2547 // the pseudo-element, to s. 2548 // 2549 // (we handle this above) 2550 } 2551 2552 Ok(()) 2553 } 2554 } 2555 2556 impl Combinator { 2557 fn to_css_internal<W>(&self, dest: &mut W, prefix_space: bool) -> fmt::Result 2558 where 2559 W: fmt::Write, 2560 { 2561 if matches!( 2562 *self, 2563 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment 2564 ) { 2565 return Ok(()); 2566 } 2567 if prefix_space { 2568 dest.write_char(' ')?; 2569 } 2570 match *self { 2571 Combinator::Child => dest.write_str("> "), 2572 Combinator::Descendant => Ok(()), 2573 Combinator::NextSibling => dest.write_str("+ "), 2574 Combinator::LaterSibling => dest.write_str("~ "), 2575 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => unsafe { 2576 debug_unreachable!("Already handled") 2577 }, 2578 } 2579 } 2580 2581 fn to_css_relative<W>(&self, dest: &mut W) -> fmt::Result 2582 where 2583 W: fmt::Write, 2584 { 2585 self.to_css_internal(dest, false) 2586 } 2587 } 2588 2589 impl ToCss for Combinator { 2590 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 2591 where 2592 W: fmt::Write, 2593 { 2594 self.to_css_internal(dest, true) 2595 } 2596 } 2597 2598 impl<Impl: SelectorImpl> ToCss for Component<Impl> { 2599 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 2600 where 2601 W: fmt::Write, 2602 { 2603 use self::Component::*; 2604 2605 match *self { 2606 Combinator(ref c) => c.to_css(dest), 2607 Slotted(ref selector) => { 2608 dest.write_str("::slotted(")?; 2609 selector.to_css(dest)?; 2610 dest.write_char(')') 2611 }, 2612 Part(ref part_names) => { 2613 dest.write_str("::part(")?; 2614 for (i, name) in part_names.iter().enumerate() { 2615 if i != 0 { 2616 dest.write_char(' ')?; 2617 } 2618 name.to_css(dest)?; 2619 } 2620 dest.write_char(')') 2621 }, 2622 PseudoElement(ref p) => p.to_css(dest), 2623 ID(ref s) => { 2624 dest.write_char('#')?; 2625 s.to_css(dest) 2626 }, 2627 Class(ref s) => { 2628 dest.write_char('.')?; 2629 s.to_css(dest) 2630 }, 2631 LocalName(ref s) => s.to_css(dest), 2632 ExplicitUniversalType => dest.write_char('*'), 2633 2634 DefaultNamespace(_) => Ok(()), 2635 ExplicitNoNamespace => dest.write_char('|'), 2636 ExplicitAnyNamespace => dest.write_str("*|"), 2637 Namespace(ref prefix, _) => { 2638 prefix.to_css(dest)?; 2639 dest.write_char('|') 2640 }, 2641 2642 AttributeInNoNamespaceExists { ref local_name, .. } => { 2643 dest.write_char('[')?; 2644 local_name.to_css(dest)?; 2645 dest.write_char(']') 2646 }, 2647 AttributeInNoNamespace { 2648 ref local_name, 2649 operator, 2650 ref value, 2651 case_sensitivity, 2652 .. 2653 } => { 2654 dest.write_char('[')?; 2655 local_name.to_css(dest)?; 2656 operator.to_css(dest)?; 2657 value.to_css(dest)?; 2658 match case_sensitivity { 2659 ParsedCaseSensitivity::CaseSensitive 2660 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => { 2661 }, 2662 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?, 2663 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?, 2664 } 2665 dest.write_char(']') 2666 }, 2667 AttributeOther(ref attr_selector) => attr_selector.to_css(dest), 2668 2669 // Pseudo-classes 2670 Root => dest.write_str(":root"), 2671 Empty => dest.write_str(":empty"), 2672 Scope => dest.write_str(":scope"), 2673 ParentSelector => dest.write_char('&'), 2674 Host(ref selector) => { 2675 dest.write_str(":host")?; 2676 if let Some(ref selector) = *selector { 2677 dest.write_char('(')?; 2678 selector.to_css(dest)?; 2679 dest.write_char(')')?; 2680 } 2681 Ok(()) 2682 }, 2683 Nth(ref nth_data) => { 2684 nth_data.write_start(dest)?; 2685 if nth_data.is_function { 2686 nth_data.write_affine(dest)?; 2687 dest.write_char(')')?; 2688 } 2689 Ok(()) 2690 }, 2691 NthOf(ref nth_of_data) => { 2692 let nth_data = nth_of_data.nth_data(); 2693 nth_data.write_start(dest)?; 2694 debug_assert!( 2695 nth_data.is_function, 2696 "A selector must be a function to hold An+B notation" 2697 ); 2698 nth_data.write_affine(dest)?; 2699 debug_assert!( 2700 matches!(nth_data.ty, NthType::Child | NthType::LastChild), 2701 "Only :nth-child or :nth-last-child can be of a selector list" 2702 ); 2703 debug_assert!( 2704 !nth_of_data.selectors().is_empty(), 2705 "The selector list should not be empty" 2706 ); 2707 dest.write_str(" of ")?; 2708 serialize_selector_list(nth_of_data.selectors().iter(), dest)?; 2709 dest.write_char(')') 2710 }, 2711 Is(ref list) | Where(ref list) | Negation(ref list) => { 2712 match *self { 2713 Where(..) => dest.write_str(":where(")?, 2714 Is(..) => dest.write_str(":is(")?, 2715 Negation(..) => dest.write_str(":not(")?, 2716 _ => unreachable!(), 2717 } 2718 serialize_selector_list(list.slice().iter(), dest)?; 2719 dest.write_str(")") 2720 }, 2721 Has(ref list) => { 2722 dest.write_str(":has(")?; 2723 serialize_selector_list(list.iter().map(|rel| &rel.selector), dest)?; 2724 dest.write_str(")") 2725 }, 2726 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest), 2727 Invalid(ref css) => dest.write_str(css), 2728 RelativeSelectorAnchor | ImplicitScope => Ok(()), 2729 } 2730 } 2731 } 2732 2733 impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> { 2734 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 2735 where 2736 W: fmt::Write, 2737 { 2738 dest.write_char('[')?; 2739 match self.namespace { 2740 Some(NamespaceConstraint::Specific((ref prefix, _))) => { 2741 prefix.to_css(dest)?; 2742 dest.write_char('|')? 2743 }, 2744 Some(NamespaceConstraint::Any) => dest.write_str("*|")?, 2745 None => {}, 2746 } 2747 self.local_name.to_css(dest)?; 2748 match self.operation { 2749 ParsedAttrSelectorOperation::Exists => {}, 2750 ParsedAttrSelectorOperation::WithValue { 2751 operator, 2752 case_sensitivity, 2753 ref value, 2754 } => { 2755 operator.to_css(dest)?; 2756 value.to_css(dest)?; 2757 match case_sensitivity { 2758 ParsedCaseSensitivity::CaseSensitive 2759 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => { 2760 }, 2761 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?, 2762 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?, 2763 } 2764 }, 2765 } 2766 dest.write_char(']') 2767 } 2768 } 2769 2770 impl<Impl: SelectorImpl> ToCss for LocalName<Impl> { 2771 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 2772 where 2773 W: fmt::Write, 2774 { 2775 self.name.to_css(dest) 2776 } 2777 } 2778 2779 /// Build up a Selector. 2780 /// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; 2781 /// 2782 /// `Err` means invalid selector. 2783 fn parse_selector<'i, 't, P, Impl>( 2784 parser: &P, 2785 input: &mut CssParser<'i, 't>, 2786 mut state: SelectorParsingState, 2787 parse_relative: ParseRelative, 2788 ) -> Result<Selector<Impl>, ParseError<'i, P::Error>> 2789 where 2790 P: Parser<'i, Impl = Impl>, 2791 Impl: SelectorImpl, 2792 { 2793 let mut builder = SelectorBuilder::default(); 2794 2795 // Helps rewind less, but also simplifies dealing with relative combinators below. 2796 input.skip_whitespace(); 2797 2798 if parse_relative != ParseRelative::No { 2799 let combinator = try_parse_combinator(input); 2800 match parse_relative { 2801 ParseRelative::ForHas => { 2802 builder.push_simple_selector(Component::RelativeSelectorAnchor); 2803 // Do we see a combinator? If so, push that. Otherwise, push a descendant 2804 // combinator. 2805 builder.push_combinator(combinator.unwrap_or(Combinator::Descendant)); 2806 }, 2807 ParseRelative::ForNesting | ParseRelative::ForScope => { 2808 if let Ok(combinator) = combinator { 2809 let selector = match parse_relative { 2810 ParseRelative::ForHas | ParseRelative::No => unreachable!(), 2811 ParseRelative::ForNesting => Component::ParentSelector, 2812 // See https://github.com/w3c/csswg-drafts/issues/10196 2813 // Implicitly added `:scope` does not add specificity 2814 // for non-relative selectors, so do the same. 2815 ParseRelative::ForScope => Component::ImplicitScope, 2816 }; 2817 builder.push_simple_selector(selector); 2818 builder.push_combinator(combinator); 2819 } 2820 }, 2821 ParseRelative::No => unreachable!(), 2822 } 2823 } 2824 loop { 2825 // Parse a sequence of simple selectors. 2826 let empty = parse_compound_selector(parser, &mut state, input, &mut builder)?; 2827 if empty { 2828 return Err(input.new_custom_error(if builder.has_combinators() { 2829 SelectorParseErrorKind::DanglingCombinator 2830 } else { 2831 SelectorParseErrorKind::EmptySelector 2832 })); 2833 } 2834 2835 if state.intersects(SelectorParsingState::AFTER_PSEUDO) { 2836 debug_assert!(state.intersects( 2837 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO 2838 | SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO 2839 | SelectorParsingState::AFTER_SLOTTED 2840 | SelectorParsingState::AFTER_PART_LIKE 2841 )); 2842 break; 2843 } 2844 2845 let combinator = if let Ok(c) = try_parse_combinator(input) { 2846 c 2847 } else { 2848 break; 2849 }; 2850 2851 if !state.allows_combinators() { 2852 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 2853 } 2854 2855 builder.push_combinator(combinator); 2856 } 2857 return Ok(Selector(builder.build(parse_relative))); 2858 } 2859 2860 fn try_parse_combinator<'i, 't>(input: &mut CssParser<'i, 't>) -> Result<Combinator, ()> { 2861 let mut any_whitespace = false; 2862 loop { 2863 let before_this_token = input.state(); 2864 match input.next_including_whitespace() { 2865 Err(_e) => return Err(()), 2866 Ok(&Token::WhiteSpace(_)) => any_whitespace = true, 2867 Ok(&Token::Delim('>')) => { 2868 return Ok(Combinator::Child); 2869 }, 2870 Ok(&Token::Delim('+')) => { 2871 return Ok(Combinator::NextSibling); 2872 }, 2873 Ok(&Token::Delim('~')) => { 2874 return Ok(Combinator::LaterSibling); 2875 }, 2876 Ok(_) => { 2877 input.reset(&before_this_token); 2878 if any_whitespace { 2879 return Ok(Combinator::Descendant); 2880 } else { 2881 return Err(()); 2882 } 2883 }, 2884 } 2885 } 2886 } 2887 2888 /// * `Err(())`: Invalid selector, abort 2889 /// * `Ok(false)`: Not a type selector, could be something else. `input` was not consumed. 2890 /// * `Ok(true)`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`) 2891 fn parse_type_selector<'i, 't, P, Impl, S>( 2892 parser: &P, 2893 input: &mut CssParser<'i, 't>, 2894 state: SelectorParsingState, 2895 sink: &mut S, 2896 ) -> Result<bool, ParseError<'i, P::Error>> 2897 where 2898 P: Parser<'i, Impl = Impl>, 2899 Impl: SelectorImpl, 2900 S: Push<Component<Impl>>, 2901 { 2902 match parse_qualified_name(parser, input, /* in_attr_selector = */ false) { 2903 Err(ParseError { 2904 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), 2905 .. 2906 }) 2907 | Ok(OptionalQName::None(_)) => Ok(false), 2908 Ok(OptionalQName::Some(namespace, local_name)) => { 2909 if state.intersects(SelectorParsingState::AFTER_PSEUDO) { 2910 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 2911 } 2912 match namespace { 2913 QNamePrefix::ImplicitAnyNamespace => {}, 2914 QNamePrefix::ImplicitDefaultNamespace(url) => { 2915 sink.push(Component::DefaultNamespace(url)) 2916 }, 2917 QNamePrefix::ExplicitNamespace(prefix, url) => { 2918 sink.push(match parser.default_namespace() { 2919 Some(ref default_url) if url == *default_url => { 2920 Component::DefaultNamespace(url) 2921 }, 2922 _ => Component::Namespace(prefix, url), 2923 }) 2924 }, 2925 QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace), 2926 QNamePrefix::ExplicitAnyNamespace => { 2927 match parser.default_namespace() { 2928 // Element type selectors that have no namespace 2929 // component (no namespace separator) represent elements 2930 // without regard to the element's namespace (equivalent 2931 // to "*|") unless a default namespace has been declared 2932 // for namespaced selectors (e.g. in CSS, in the style 2933 // sheet). If a default namespace has been declared, 2934 // such selectors will represent only elements in the 2935 // default namespace. 2936 // -- Selectors § 6.1.1 2937 // So we'll have this act the same as the 2938 // QNamePrefix::ImplicitAnyNamespace case. 2939 None => {}, 2940 Some(_) => sink.push(Component::ExplicitAnyNamespace), 2941 } 2942 }, 2943 QNamePrefix::ImplicitNoNamespace => { 2944 unreachable!() // Not returned with in_attr_selector = false 2945 }, 2946 } 2947 match local_name { 2948 Some(name) => sink.push(Component::LocalName(LocalName { 2949 lower_name: to_ascii_lowercase(&name).as_ref().into(), 2950 name: name.as_ref().into(), 2951 })), 2952 None => sink.push(Component::ExplicitUniversalType), 2953 } 2954 Ok(true) 2955 }, 2956 Err(e) => Err(e), 2957 } 2958 } 2959 2960 #[derive(Debug)] 2961 enum SimpleSelectorParseResult<Impl: SelectorImpl> { 2962 SimpleSelector(Component<Impl>), 2963 PseudoElement(Impl::PseudoElement), 2964 SlottedPseudo(Selector<Impl>), 2965 PartPseudo(Box<[Impl::Identifier]>), 2966 } 2967 2968 #[derive(Debug)] 2969 enum QNamePrefix<Impl: SelectorImpl> { 2970 ImplicitNoNamespace, // `foo` in attr selectors 2971 ImplicitAnyNamespace, // `foo` in type selectors, without a default ns 2972 ImplicitDefaultNamespace(Impl::NamespaceUrl), // `foo` in type selectors, with a default ns 2973 ExplicitNoNamespace, // `|foo` 2974 ExplicitAnyNamespace, // `*|foo` 2975 ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo` 2976 } 2977 2978 enum OptionalQName<'i, Impl: SelectorImpl> { 2979 Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>), 2980 None(Token<'i>), 2981 } 2982 2983 /// * `Err(())`: Invalid selector, abort 2984 /// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed, 2985 /// but the token is still returned. 2986 /// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector 2987 fn parse_qualified_name<'i, 't, P, Impl>( 2988 parser: &P, 2989 input: &mut CssParser<'i, 't>, 2990 in_attr_selector: bool, 2991 ) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>> 2992 where 2993 P: Parser<'i, Impl = Impl>, 2994 Impl: SelectorImpl, 2995 { 2996 let default_namespace = |local_name| { 2997 let namespace = match parser.default_namespace() { 2998 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url), 2999 None => QNamePrefix::ImplicitAnyNamespace, 3000 }; 3001 Ok(OptionalQName::Some(namespace, local_name)) 3002 }; 3003 3004 let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| { 3005 let location = input.current_source_location(); 3006 match input.next_including_whitespace() { 3007 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)), 3008 Ok(&Token::Ident(ref local_name)) => { 3009 Ok(OptionalQName::Some(namespace, Some(local_name.clone()))) 3010 }, 3011 Ok(t) if in_attr_selector => { 3012 let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone()); 3013 Err(location.new_custom_error(e)) 3014 }, 3015 Ok(t) => Err(location.new_custom_error( 3016 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()), 3017 )), 3018 Err(e) => Err(e.into()), 3019 } 3020 }; 3021 3022 let start = input.state(); 3023 match input.next_including_whitespace() { 3024 Ok(Token::Ident(value)) => { 3025 let value = value.clone(); 3026 let after_ident = input.state(); 3027 match input.next_including_whitespace() { 3028 Ok(&Token::Delim('|')) => { 3029 let prefix = value.as_ref().into(); 3030 let result = parser.namespace_for_prefix(&prefix); 3031 let url = result.ok_or( 3032 after_ident 3033 .source_location() 3034 .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)), 3035 )?; 3036 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url)) 3037 }, 3038 _ => { 3039 input.reset(&after_ident); 3040 if in_attr_selector { 3041 Ok(OptionalQName::Some( 3042 QNamePrefix::ImplicitNoNamespace, 3043 Some(value), 3044 )) 3045 } else { 3046 default_namespace(Some(value)) 3047 } 3048 }, 3049 } 3050 }, 3051 Ok(Token::Delim('*')) => { 3052 let after_star = input.state(); 3053 match input.next_including_whitespace() { 3054 Ok(&Token::Delim('|')) => { 3055 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace) 3056 }, 3057 _ if !in_attr_selector => { 3058 input.reset(&after_star); 3059 default_namespace(None) 3060 }, 3061 result => { 3062 let t = result?; 3063 Err(after_star 3064 .source_location() 3065 .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t.clone()))) 3066 }, 3067 } 3068 }, 3069 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace), 3070 Ok(t) => { 3071 let t = t.clone(); 3072 input.reset(&start); 3073 Ok(OptionalQName::None(t)) 3074 }, 3075 Err(e) => { 3076 input.reset(&start); 3077 Err(e.into()) 3078 }, 3079 } 3080 } 3081 3082 fn parse_attribute_selector<'i, 't, P, Impl>( 3083 parser: &P, 3084 input: &mut CssParser<'i, 't>, 3085 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3086 where 3087 P: Parser<'i, Impl = Impl>, 3088 Impl: SelectorImpl, 3089 { 3090 let namespace; 3091 let local_name; 3092 3093 input.skip_whitespace(); 3094 3095 match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { 3096 OptionalQName::None(t) => { 3097 return Err(input.new_custom_error( 3098 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t), 3099 )); 3100 }, 3101 OptionalQName::Some(_, None) => unreachable!(), 3102 OptionalQName::Some(ns, Some(ln)) => { 3103 local_name = ln; 3104 namespace = match ns { 3105 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None, 3106 QNamePrefix::ExplicitNamespace(prefix, url) => { 3107 Some(NamespaceConstraint::Specific((prefix, url))) 3108 }, 3109 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any), 3110 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => { 3111 unreachable!() // Not returned with in_attr_selector = true 3112 }, 3113 } 3114 }, 3115 } 3116 3117 let location = input.current_source_location(); 3118 let operator = match input.next() { 3119 // [foo] 3120 Err(_) => { 3121 let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into(); 3122 let local_name = local_name.as_ref().into(); 3123 if let Some(namespace) = namespace { 3124 return Ok(Component::AttributeOther(Box::new( 3125 AttrSelectorWithOptionalNamespace { 3126 namespace: Some(namespace), 3127 local_name, 3128 local_name_lower, 3129 operation: ParsedAttrSelectorOperation::Exists, 3130 }, 3131 ))); 3132 } else { 3133 return Ok(Component::AttributeInNoNamespaceExists { 3134 local_name, 3135 local_name_lower, 3136 }); 3137 } 3138 }, 3139 3140 // [foo=bar] 3141 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal, 3142 // [foo~=bar] 3143 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes, 3144 // [foo|=bar] 3145 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch, 3146 // [foo^=bar] 3147 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix, 3148 // [foo*=bar] 3149 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring, 3150 // [foo$=bar] 3151 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix, 3152 Ok(t) => { 3153 return Err(location.new_custom_error( 3154 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()), 3155 )); 3156 }, 3157 }; 3158 3159 let value = match input.expect_ident_or_string() { 3160 Ok(t) => t.clone(), 3161 Err(BasicParseError { 3162 kind: BasicParseErrorKind::UnexpectedToken(t), 3163 location, 3164 }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))), 3165 Err(e) => return Err(e.into()), 3166 }; 3167 3168 let attribute_flags = parse_attribute_flags(input)?; 3169 let value = value.as_ref().into(); 3170 let local_name_lower; 3171 let local_name_is_ascii_lowercase; 3172 let case_sensitivity; 3173 { 3174 let local_name_lower_cow = to_ascii_lowercase(&local_name); 3175 case_sensitivity = 3176 attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some()); 3177 local_name_lower = local_name_lower_cow.as_ref().into(); 3178 local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..)); 3179 } 3180 let local_name = local_name.as_ref().into(); 3181 if namespace.is_some() || !local_name_is_ascii_lowercase { 3182 Ok(Component::AttributeOther(Box::new( 3183 AttrSelectorWithOptionalNamespace { 3184 namespace, 3185 local_name, 3186 local_name_lower, 3187 operation: ParsedAttrSelectorOperation::WithValue { 3188 operator, 3189 case_sensitivity, 3190 value, 3191 }, 3192 }, 3193 ))) 3194 } else { 3195 Ok(Component::AttributeInNoNamespace { 3196 local_name, 3197 operator, 3198 value, 3199 case_sensitivity, 3200 }) 3201 } 3202 } 3203 3204 /// An attribute selector can have 's' or 'i' as flags, or no flags at all. 3205 enum AttributeFlags { 3206 // Matching should be case-sensitive ('s' flag). 3207 CaseSensitive, 3208 // Matching should be case-insensitive ('i' flag). 3209 AsciiCaseInsensitive, 3210 // No flags. Matching behavior depends on the name of the attribute. 3211 CaseSensitivityDependsOnName, 3212 } 3213 3214 impl AttributeFlags { 3215 fn to_case_sensitivity( 3216 self, 3217 local_name_lower: &str, 3218 have_namespace: bool, 3219 ) -> ParsedCaseSensitivity { 3220 match self { 3221 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive, 3222 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive, 3223 AttributeFlags::CaseSensitivityDependsOnName => { 3224 if !have_namespace 3225 && include!(concat!( 3226 env!("OUT_DIR"), 3227 "/ascii_case_insensitive_html_attributes.rs" 3228 )) 3229 .contains(local_name_lower) 3230 { 3231 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument 3232 } else { 3233 ParsedCaseSensitivity::CaseSensitive 3234 } 3235 }, 3236 } 3237 } 3238 } 3239 3240 fn parse_attribute_flags<'i, 't>( 3241 input: &mut CssParser<'i, 't>, 3242 ) -> Result<AttributeFlags, BasicParseError<'i>> { 3243 let location = input.current_source_location(); 3244 let token = match input.next() { 3245 Ok(t) => t, 3246 Err(..) => { 3247 // Selectors spec says language-defined; HTML says it depends on the 3248 // exact attribute name. 3249 return Ok(AttributeFlags::CaseSensitivityDependsOnName); 3250 }, 3251 }; 3252 3253 let ident = match *token { 3254 Token::Ident(ref i) => i, 3255 ref other => return Err(location.new_basic_unexpected_token_error(other.clone())), 3256 }; 3257 3258 Ok(match_ignore_ascii_case! { 3259 ident, 3260 "i" => AttributeFlags::AsciiCaseInsensitive, 3261 "s" => AttributeFlags::CaseSensitive, 3262 _ => return Err(location.new_basic_unexpected_token_error(token.clone())), 3263 }) 3264 } 3265 3266 /// Level 3: Parse **one** simple_selector. (Though we might insert a second 3267 /// implied "<defaultns>|*" type selector.) 3268 fn parse_negation<'i, 't, P, Impl>( 3269 parser: &P, 3270 input: &mut CssParser<'i, 't>, 3271 state: SelectorParsingState, 3272 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3273 where 3274 P: Parser<'i, Impl = Impl>, 3275 Impl: SelectorImpl, 3276 { 3277 let list = SelectorList::parse_with_state( 3278 parser, 3279 input, 3280 state 3281 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE 3282 | SelectorParsingState::DISALLOW_PSEUDOS, 3283 ForgivingParsing::No, 3284 ParseRelative::No, 3285 )?; 3286 3287 Ok(Component::Negation(list)) 3288 } 3289 3290 /// simple_selector_sequence 3291 /// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]* 3292 /// | [ HASH | class | attrib | pseudo | negation ]+ 3293 /// 3294 /// `Err(())` means invalid selector. 3295 /// `Ok(true)` is an empty selector 3296 fn parse_compound_selector<'i, 't, P, Impl>( 3297 parser: &P, 3298 state: &mut SelectorParsingState, 3299 input: &mut CssParser<'i, 't>, 3300 builder: &mut SelectorBuilder<Impl>, 3301 ) -> Result<bool, ParseError<'i, P::Error>> 3302 where 3303 P: Parser<'i, Impl = Impl>, 3304 Impl: SelectorImpl, 3305 { 3306 input.skip_whitespace(); 3307 3308 let mut empty = true; 3309 if parse_type_selector(parser, input, *state, builder)? { 3310 empty = false; 3311 } 3312 3313 loop { 3314 let result = match parse_one_simple_selector(parser, input, *state)? { 3315 None => break, 3316 Some(result) => result, 3317 }; 3318 3319 if empty { 3320 if let Some(url) = parser.default_namespace() { 3321 // If there was no explicit type selector, but there is a 3322 // default namespace, there is an implicit "<defaultns>|*" type 3323 // selector. Except for :host() or :not() / :is() / :where(), 3324 // where we ignore it. 3325 // 3326 // https://drafts.csswg.org/css-scoping/#host-element-in-tree: 3327 // 3328 // When considered within its own shadow trees, the shadow 3329 // host is featureless. Only the :host, :host(), and 3330 // :host-context() pseudo-classes are allowed to match it. 3331 // 3332 // https://drafts.csswg.org/selectors-4/#featureless: 3333 // 3334 // A featureless element does not match any selector at all, 3335 // except those it is explicitly defined to match. If a 3336 // given selector is allowed to match a featureless element, 3337 // it must do so while ignoring the default namespace. 3338 // 3339 // https://drafts.csswg.org/selectors-4/#matches 3340 // 3341 // Default namespace declarations do not affect the compound 3342 // selector representing the subject of any selector within 3343 // a :is() pseudo-class, unless that compound selector 3344 // contains an explicit universal selector or type selector. 3345 // 3346 // (Similar quotes for :where() / :not()) 3347 // 3348 let ignore_default_ns = state 3349 .intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE) 3350 || matches!( 3351 result, 3352 SimpleSelectorParseResult::SimpleSelector(Component::Host(..)) 3353 ); 3354 if !ignore_default_ns { 3355 builder.push_simple_selector(Component::DefaultNamespace(url)); 3356 } 3357 } 3358 } 3359 3360 empty = false; 3361 3362 match result { 3363 SimpleSelectorParseResult::SimpleSelector(s) => { 3364 builder.push_simple_selector(s); 3365 }, 3366 SimpleSelectorParseResult::PartPseudo(part_names) => { 3367 state.insert(SelectorParsingState::AFTER_PART_LIKE); 3368 builder.push_combinator(Combinator::Part); 3369 builder.push_simple_selector(Component::Part(part_names)); 3370 }, 3371 SimpleSelectorParseResult::SlottedPseudo(selector) => { 3372 state.insert(SelectorParsingState::AFTER_SLOTTED); 3373 builder.push_combinator(Combinator::SlotAssignment); 3374 builder.push_simple_selector(Component::Slotted(selector)); 3375 }, 3376 SimpleSelectorParseResult::PseudoElement(p) => { 3377 if p.is_element_backed() { 3378 state.insert(SelectorParsingState::AFTER_PART_LIKE); 3379 } else { 3380 state.insert(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO); 3381 if p.is_before_or_after() { 3382 state.insert(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO); 3383 } 3384 } 3385 if !p.accepts_state_pseudo_classes() { 3386 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT); 3387 } 3388 if p.is_in_pseudo_element_tree() { 3389 state.insert(SelectorParsingState::IN_PSEUDO_ELEMENT_TREE); 3390 } 3391 builder.push_combinator(Combinator::PseudoElement); 3392 builder.push_simple_selector(Component::PseudoElement(p)); 3393 }, 3394 } 3395 } 3396 Ok(empty) 3397 } 3398 3399 fn parse_is_where<'i, 't, P, Impl>( 3400 parser: &P, 3401 input: &mut CssParser<'i, 't>, 3402 state: SelectorParsingState, 3403 component: impl FnOnce(SelectorList<Impl>) -> Component<Impl>, 3404 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3405 where 3406 P: Parser<'i, Impl = Impl>, 3407 Impl: SelectorImpl, 3408 { 3409 debug_assert!(parser.parse_is_and_where()); 3410 // https://drafts.csswg.org/selectors/#matches-pseudo: 3411 // 3412 // Pseudo-elements cannot be represented by the matches-any 3413 // pseudo-class; they are not valid within :is(). 3414 // 3415 let inner = SelectorList::parse_with_state( 3416 parser, 3417 input, 3418 state 3419 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE 3420 | SelectorParsingState::DISALLOW_PSEUDOS, 3421 ForgivingParsing::Yes, 3422 ParseRelative::No, 3423 )?; 3424 Ok(component(inner)) 3425 } 3426 3427 fn parse_has<'i, 't, P, Impl>( 3428 parser: &P, 3429 input: &mut CssParser<'i, 't>, 3430 state: SelectorParsingState, 3431 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3432 where 3433 P: Parser<'i, Impl = Impl>, 3434 Impl: SelectorImpl, 3435 { 3436 debug_assert!(parser.parse_has()); 3437 if state.intersects( 3438 SelectorParsingState::DISALLOW_RELATIVE_SELECTOR | SelectorParsingState::AFTER_PSEUDO, 3439 ) { 3440 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3441 } 3442 // Nested `:has()` is disallowed, mark it as such. 3443 // Note: The spec defines ":has-allowed pseudo-element," but there's no 3444 // pseudo-element defined as such at the moment. 3445 // https://w3c.github.io/csswg-drafts/selectors-4/#has-allowed-pseudo-element 3446 let inner = SelectorList::parse_with_state( 3447 parser, 3448 input, 3449 state 3450 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE 3451 | SelectorParsingState::DISALLOW_PSEUDOS 3452 | SelectorParsingState::DISALLOW_RELATIVE_SELECTOR, 3453 ForgivingParsing::No, 3454 ParseRelative::ForHas, 3455 )?; 3456 Ok(Component::Has(RelativeSelector::from_selector_list(inner))) 3457 } 3458 3459 fn parse_functional_pseudo_class<'i, 't, P, Impl>( 3460 parser: &P, 3461 input: &mut CssParser<'i, 't>, 3462 name: CowRcStr<'i>, 3463 state: SelectorParsingState, 3464 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3465 where 3466 P: Parser<'i, Impl = Impl>, 3467 Impl: SelectorImpl, 3468 { 3469 match_ignore_ascii_case! { &name, 3470 "nth-child" => return parse_nth_pseudo_class(parser, input, state, NthType::Child), 3471 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::OfType), 3472 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, NthType::LastChild), 3473 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::LastOfType), 3474 "is" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Is), 3475 "where" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Where), 3476 "has" if parser.parse_has() => return parse_has(parser, input, state), 3477 "host" => { 3478 if !state.allows_tree_structural_pseudo_classes() { 3479 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3480 } 3481 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?))); 3482 }, 3483 "not" => { 3484 return parse_negation(parser, input, state) 3485 }, 3486 _ => {} 3487 } 3488 3489 if parser.parse_is_and_where() && parser.is_is_alias(&name) { 3490 return parse_is_where(parser, input, state, Component::Is); 3491 } 3492 3493 if state.intersects( 3494 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO | SelectorParsingState::AFTER_SLOTTED, 3495 ) { 3496 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3497 } 3498 3499 let after_part = state.intersects(SelectorParsingState::AFTER_PART_LIKE); 3500 P::parse_non_ts_functional_pseudo_class(parser, name, input, after_part) 3501 .map(Component::NonTSPseudoClass) 3502 } 3503 3504 fn parse_nth_pseudo_class<'i, 't, P, Impl>( 3505 parser: &P, 3506 input: &mut CssParser<'i, 't>, 3507 state: SelectorParsingState, 3508 ty: NthType, 3509 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3510 where 3511 P: Parser<'i, Impl = Impl>, 3512 Impl: SelectorImpl, 3513 { 3514 if !state.allows_tree_structural_pseudo_classes() { 3515 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3516 } 3517 let (a, b) = parse_nth(input)?; 3518 let nth_data = NthSelectorData { 3519 ty, 3520 is_function: true, 3521 an_plus_b: AnPlusB(a, b), 3522 }; 3523 if !parser.parse_nth_child_of() || ty.is_of_type() { 3524 return Ok(Component::Nth(nth_data)); 3525 } 3526 3527 // Try to parse "of <selector-list>". 3528 if input.try_parse(|i| i.expect_ident_matching("of")).is_err() { 3529 return Ok(Component::Nth(nth_data)); 3530 } 3531 // Whitespace between "of" and the selector list is optional 3532 // https://github.com/w3c/csswg-drafts/issues/8285 3533 let selectors = SelectorList::parse_with_state( 3534 parser, 3535 input, 3536 state 3537 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE 3538 | SelectorParsingState::DISALLOW_PSEUDOS, 3539 ForgivingParsing::No, 3540 ParseRelative::No, 3541 )?; 3542 Ok(Component::NthOf(NthOfSelectorData::new( 3543 &nth_data, 3544 selectors.slice().iter().cloned(), 3545 ))) 3546 } 3547 3548 /// Returns whether the name corresponds to a CSS2 pseudo-element that 3549 /// can be specified with the single colon syntax (in addition to the 3550 /// double-colon syntax, which can be used for all pseudo-elements). 3551 pub fn is_css2_pseudo_element(name: &str) -> bool { 3552 // ** Do not add to this list! ** 3553 match_ignore_ascii_case! { name, 3554 "before" | "after" | "first-line" | "first-letter" => true, 3555 _ => false, 3556 } 3557 } 3558 3559 /// Parse a simple selector other than a type selector. 3560 /// 3561 /// * `Err(())`: Invalid selector, abort 3562 /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. 3563 /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element 3564 fn parse_one_simple_selector<'i, 't, P, Impl>( 3565 parser: &P, 3566 input: &mut CssParser<'i, 't>, 3567 state: SelectorParsingState, 3568 ) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>> 3569 where 3570 P: Parser<'i, Impl = Impl>, 3571 Impl: SelectorImpl, 3572 { 3573 let start = input.state(); 3574 let token = match input.next_including_whitespace().map(|t| t.clone()) { 3575 Ok(t) => t, 3576 Err(..) => { 3577 input.reset(&start); 3578 return Ok(None); 3579 }, 3580 }; 3581 3582 Ok(Some(match token { 3583 Token::IDHash(id) => { 3584 if state.intersects(SelectorParsingState::AFTER_PSEUDO) { 3585 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3586 } 3587 let id = Component::ID(id.as_ref().into()); 3588 SimpleSelectorParseResult::SimpleSelector(id) 3589 }, 3590 Token::Delim(delim) if delim == '.' || (delim == '&' && parser.parse_parent_selector()) => { 3591 if state.intersects(SelectorParsingState::AFTER_PSEUDO) { 3592 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3593 } 3594 let location = input.current_source_location(); 3595 SimpleSelectorParseResult::SimpleSelector(if delim == '&' { 3596 Component::ParentSelector 3597 } else { 3598 let class = match *input.next_including_whitespace()? { 3599 Token::Ident(ref class) => class, 3600 ref t => { 3601 let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone()); 3602 return Err(location.new_custom_error(e)); 3603 }, 3604 }; 3605 Component::Class(class.as_ref().into()) 3606 }) 3607 }, 3608 Token::SquareBracketBlock => { 3609 if state.intersects(SelectorParsingState::AFTER_PSEUDO) { 3610 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3611 } 3612 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?; 3613 SimpleSelectorParseResult::SimpleSelector(attr) 3614 }, 3615 Token::Colon => { 3616 let location = input.current_source_location(); 3617 let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() { 3618 Token::Colon => (false, input.next_including_whitespace()?.clone()), 3619 t => (true, t), 3620 }; 3621 let (name, is_functional) = match next_token { 3622 Token::Ident(name) => (name, false), 3623 Token::Function(name) => (name, true), 3624 t => { 3625 let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t); 3626 return Err(input.new_custom_error(e)); 3627 }, 3628 }; 3629 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name); 3630 if is_pseudo_element { 3631 // Pseudos after pseudo elements are not allowed in some cases: 3632 // - Some states will disallow pseudos, such as the interiors of 3633 // :has/:is/:where/:not (DISALLOW_PSEUDOS). 3634 // - Non-element backed pseudos do not allow other pseudos to follow (AFTER_NON_ELEMENT_BACKED_PSEUDO)... 3635 // - ... except ::before and ::after, which allow _some_ pseudos. 3636 if state.intersects(SelectorParsingState::DISALLOW_PSEUDOS) 3637 || (state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO) 3638 && !state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO)) 3639 { 3640 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3641 } 3642 let pseudo_element = if is_functional { 3643 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") { 3644 if !state.allows_part() { 3645 return Err( 3646 input.new_custom_error(SelectorParseErrorKind::InvalidState) 3647 ); 3648 } 3649 let names = input.parse_nested_block(|input| { 3650 let mut result = Vec::with_capacity(1); 3651 result.push(input.expect_ident()?.as_ref().into()); 3652 while !input.is_exhausted() { 3653 result.push(input.expect_ident()?.as_ref().into()); 3654 } 3655 Ok(result.into_boxed_slice()) 3656 })?; 3657 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names))); 3658 } 3659 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") { 3660 if !state.allows_slotted() { 3661 return Err( 3662 input.new_custom_error(SelectorParseErrorKind::InvalidState) 3663 ); 3664 } 3665 let selector = input.parse_nested_block(|input| { 3666 parse_inner_compound_selector(parser, input, state) 3667 })?; 3668 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector))); 3669 } 3670 input.parse_nested_block(|input| { 3671 P::parse_functional_pseudo_element(parser, name, input) 3672 })? 3673 } else { 3674 P::parse_pseudo_element(parser, location, name)? 3675 }; 3676 3677 if state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO) 3678 && !pseudo_element.valid_after_before_or_after() 3679 { 3680 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3681 } 3682 3683 if state.intersects(SelectorParsingState::AFTER_SLOTTED) 3684 && !pseudo_element.valid_after_slotted() 3685 { 3686 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState)); 3687 } 3688 SimpleSelectorParseResult::PseudoElement(pseudo_element) 3689 } else { 3690 let pseudo_class = if is_functional { 3691 input.parse_nested_block(|input| { 3692 parse_functional_pseudo_class(parser, input, name, state) 3693 })? 3694 } else { 3695 parse_simple_pseudo_class(parser, location, name, state)? 3696 }; 3697 SimpleSelectorParseResult::SimpleSelector(pseudo_class) 3698 } 3699 }, 3700 _ => { 3701 input.reset(&start); 3702 return Ok(None); 3703 }, 3704 })) 3705 } 3706 3707 fn parse_simple_pseudo_class<'i, P, Impl>( 3708 parser: &P, 3709 location: SourceLocation, 3710 name: CowRcStr<'i>, 3711 state: SelectorParsingState, 3712 ) -> Result<Component<Impl>, ParseError<'i, P::Error>> 3713 where 3714 P: Parser<'i, Impl = Impl>, 3715 Impl: SelectorImpl, 3716 { 3717 if !state.allows_non_functional_pseudo_classes() { 3718 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState)); 3719 } 3720 3721 if state.allows_tree_structural_pseudo_classes() { 3722 // If a descendant pseudo of a pseudo-element root has no other siblings, then :only-child 3723 // matches that pseudo. Note that we don't accept other tree structural pseudo classes in 3724 // this case (to match other browsers). And the spec mentions only `:only-child` as well. 3725 // https://drafts.csswg.org/css-view-transitions-1/#pseudo-root 3726 if state.allows_only_child_pseudo_class_only() { 3727 if name.eq_ignore_ascii_case("only-child") { 3728 return Ok(Component::Nth(NthSelectorData::only( 3729 /* of_type = */ false, 3730 ))); 3731 } 3732 // Other non-functional pseudo classes are not allowed. 3733 // FIXME: Perhaps we can refactor this, e.g. distinguish tree-structural pseudo classes 3734 // from other non-ts pseudo classes. Otherwise, this special case looks weird. 3735 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState)); 3736 } 3737 3738 match_ignore_ascii_case! { &name, 3739 "first-child" => return Ok(Component::Nth(NthSelectorData::first(/* of_type = */ false))), 3740 "last-child" => return Ok(Component::Nth(NthSelectorData::last(/* of_type = */ false))), 3741 "only-child" => return Ok(Component::Nth(NthSelectorData::only(/* of_type = */ false))), 3742 "root" => return Ok(Component::Root), 3743 "empty" => return Ok(Component::Empty), 3744 "scope" => return Ok(Component::Scope), 3745 "host" if P::parse_host(parser) => return Ok(Component::Host(None)), 3746 "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(/* of_type = */ true))), 3747 "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(/* of_type = */ true))), 3748 "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(/* of_type = */ true))), 3749 _ => {}, 3750 } 3751 } 3752 3753 let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?; 3754 if state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO) 3755 && !pseudo_class.is_user_action_state() 3756 { 3757 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState)); 3758 } 3759 Ok(Component::NonTSPseudoClass(pseudo_class)) 3760 } 3761 3762 // NB: pub module in order to access the DummyParser 3763 #[cfg(test)] 3764 pub mod tests { 3765 use super::*; 3766 use crate::builder::SelectorFlags; 3767 use crate::parser; 3768 use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss}; 3769 use std::collections::HashMap; 3770 use std::fmt; 3771 3772 #[derive(Clone, Debug, Eq, PartialEq)] 3773 pub enum PseudoClass { 3774 Hover, 3775 Active, 3776 Lang(String), 3777 } 3778 3779 #[derive(Clone, Debug, Eq, PartialEq)] 3780 pub enum PseudoElement { 3781 Before, 3782 After, 3783 Marker, 3784 DetailsContent, 3785 Highlight(String), 3786 } 3787 3788 impl parser::PseudoElement for PseudoElement { 3789 type Impl = DummySelectorImpl; 3790 3791 fn accepts_state_pseudo_classes(&self) -> bool { 3792 true 3793 } 3794 3795 fn valid_after_slotted(&self) -> bool { 3796 true 3797 } 3798 3799 fn valid_after_before_or_after(&self) -> bool { 3800 matches!(self, Self::Marker) 3801 } 3802 3803 fn is_before_or_after(&self) -> bool { 3804 matches!(self, Self::Before | Self::After) 3805 } 3806 3807 fn is_element_backed(&self) -> bool { 3808 matches!(self, Self::DetailsContent) 3809 } 3810 } 3811 3812 impl parser::NonTSPseudoClass for PseudoClass { 3813 type Impl = DummySelectorImpl; 3814 3815 #[inline] 3816 fn is_active_or_hover(&self) -> bool { 3817 matches!(*self, PseudoClass::Active | PseudoClass::Hover) 3818 } 3819 3820 #[inline] 3821 fn is_user_action_state(&self) -> bool { 3822 self.is_active_or_hover() 3823 } 3824 } 3825 3826 impl ToCss for PseudoClass { 3827 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 3828 where 3829 W: fmt::Write, 3830 { 3831 match *self { 3832 PseudoClass::Hover => dest.write_str(":hover"), 3833 PseudoClass::Active => dest.write_str(":active"), 3834 PseudoClass::Lang(ref lang) => { 3835 dest.write_str(":lang(")?; 3836 serialize_identifier(lang, dest)?; 3837 dest.write_char(')') 3838 }, 3839 } 3840 } 3841 } 3842 3843 impl ToCss for PseudoElement { 3844 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 3845 where 3846 W: fmt::Write, 3847 { 3848 match *self { 3849 PseudoElement::Before => dest.write_str("::before"), 3850 PseudoElement::After => dest.write_str("::after"), 3851 PseudoElement::Marker => dest.write_str("::marker"), 3852 PseudoElement::DetailsContent => dest.write_str("::details-content"), 3853 PseudoElement::Highlight(ref name) => { 3854 dest.write_str("::highlight(")?; 3855 serialize_identifier(&name, dest)?; 3856 dest.write_char(')') 3857 }, 3858 } 3859 } 3860 } 3861 3862 #[derive(Clone, Debug, PartialEq)] 3863 pub struct DummySelectorImpl; 3864 3865 #[derive(Default)] 3866 pub struct DummyParser { 3867 default_ns: Option<DummyAtom>, 3868 ns_prefixes: HashMap<DummyAtom, DummyAtom>, 3869 } 3870 3871 impl DummyParser { 3872 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser { 3873 DummyParser { 3874 default_ns: Some(default_ns), 3875 ns_prefixes: Default::default(), 3876 } 3877 } 3878 } 3879 3880 impl SelectorImpl for DummySelectorImpl { 3881 type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>; 3882 type AttrValue = DummyAttrValue; 3883 type Identifier = DummyAtom; 3884 type LocalName = DummyAtom; 3885 type NamespaceUrl = DummyAtom; 3886 type NamespacePrefix = DummyAtom; 3887 type BorrowedLocalName = DummyAtom; 3888 type BorrowedNamespaceUrl = DummyAtom; 3889 type NonTSPseudoClass = PseudoClass; 3890 type PseudoElement = PseudoElement; 3891 } 3892 3893 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] 3894 pub struct DummyAttrValue(String); 3895 3896 impl ToCss for DummyAttrValue { 3897 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 3898 where 3899 W: fmt::Write, 3900 { 3901 use std::fmt::Write; 3902 3903 dest.write_char('"')?; 3904 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)?; 3905 dest.write_char('"') 3906 } 3907 } 3908 3909 impl<'a> From<&'a str> for DummyAttrValue { 3910 fn from(string: &'a str) -> Self { 3911 Self(string.into()) 3912 } 3913 } 3914 3915 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] 3916 pub struct DummyAtom(String); 3917 3918 impl ToCss for DummyAtom { 3919 fn to_css<W>(&self, dest: &mut W) -> fmt::Result 3920 where 3921 W: fmt::Write, 3922 { 3923 serialize_identifier(&self.0, dest) 3924 } 3925 } 3926 3927 impl From<String> for DummyAtom { 3928 fn from(string: String) -> Self { 3929 DummyAtom(string) 3930 } 3931 } 3932 3933 impl<'a> From<&'a str> for DummyAtom { 3934 fn from(string: &'a str) -> Self { 3935 DummyAtom(string.into()) 3936 } 3937 } 3938 3939 impl PrecomputedHash for DummyAtom { 3940 fn precomputed_hash(&self) -> u32 { 3941 self.0.as_ptr() as u32 3942 } 3943 } 3944 3945 impl<'i> Parser<'i> for DummyParser { 3946 type Impl = DummySelectorImpl; 3947 type Error = SelectorParseErrorKind<'i>; 3948 3949 fn parse_slotted(&self) -> bool { 3950 true 3951 } 3952 3953 fn parse_nth_child_of(&self) -> bool { 3954 true 3955 } 3956 3957 fn parse_is_and_where(&self) -> bool { 3958 true 3959 } 3960 3961 fn parse_has(&self) -> bool { 3962 true 3963 } 3964 3965 fn parse_parent_selector(&self) -> bool { 3966 true 3967 } 3968 3969 fn parse_part(&self) -> bool { 3970 true 3971 } 3972 3973 fn parse_host(&self) -> bool { 3974 true 3975 } 3976 3977 fn parse_non_ts_pseudo_class( 3978 &self, 3979 location: SourceLocation, 3980 name: CowRcStr<'i>, 3981 ) -> Result<PseudoClass, SelectorParseError<'i>> { 3982 match_ignore_ascii_case! { &name, 3983 "hover" => return Ok(PseudoClass::Hover), 3984 "active" => return Ok(PseudoClass::Active), 3985 _ => {} 3986 } 3987 Err( 3988 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 3989 name, 3990 )), 3991 ) 3992 } 3993 3994 fn parse_non_ts_functional_pseudo_class<'t>( 3995 &self, 3996 name: CowRcStr<'i>, 3997 parser: &mut CssParser<'i, 't>, 3998 after_part: bool, 3999 ) -> Result<PseudoClass, SelectorParseError<'i>> { 4000 match_ignore_ascii_case! { &name, 4001 "lang" if !after_part => { 4002 let lang = parser.expect_ident_or_string()?.as_ref().to_owned(); 4003 return Ok(PseudoClass::Lang(lang)); 4004 }, 4005 _ => {} 4006 } 4007 Err( 4008 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 4009 name, 4010 )), 4011 ) 4012 } 4013 4014 fn parse_pseudo_element( 4015 &self, 4016 location: SourceLocation, 4017 name: CowRcStr<'i>, 4018 ) -> Result<PseudoElement, SelectorParseError<'i>> { 4019 match_ignore_ascii_case! { &name, 4020 "before" => return Ok(PseudoElement::Before), 4021 "after" => return Ok(PseudoElement::After), 4022 "marker" => return Ok(PseudoElement::Marker), 4023 "details-content" => return Ok(PseudoElement::DetailsContent), 4024 _ => {} 4025 } 4026 Err( 4027 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 4028 name, 4029 )), 4030 ) 4031 } 4032 4033 fn parse_functional_pseudo_element<'t>( 4034 &self, 4035 name: CowRcStr<'i>, 4036 parser: &mut CssParser<'i, 't>, 4037 ) -> Result<PseudoElement, SelectorParseError<'i>> { 4038 match_ignore_ascii_case! {&name, 4039 "highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())), 4040 _ => {} 4041 } 4042 Err( 4043 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement( 4044 name, 4045 )), 4046 ) 4047 } 4048 4049 fn default_namespace(&self) -> Option<DummyAtom> { 4050 self.default_ns.clone() 4051 } 4052 4053 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> { 4054 self.ns_prefixes.get(prefix).cloned() 4055 } 4056 } 4057 4058 fn parse<'i>( 4059 input: &'i str, 4060 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4061 parse_relative(input, ParseRelative::No) 4062 } 4063 4064 fn parse_relative<'i>( 4065 input: &'i str, 4066 parse_relative: ParseRelative, 4067 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4068 parse_ns_relative(input, &DummyParser::default(), parse_relative) 4069 } 4070 4071 fn parse_expected<'i, 'a>( 4072 input: &'i str, 4073 expected: Option<&'a str>, 4074 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4075 parse_ns_expected(input, &DummyParser::default(), expected) 4076 } 4077 4078 fn parse_relative_expected<'i, 'a>( 4079 input: &'i str, 4080 parse_relative: ParseRelative, 4081 expected: Option<&'a str>, 4082 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4083 parse_ns_relative_expected(input, &DummyParser::default(), parse_relative, expected) 4084 } 4085 4086 fn parse_ns<'i>( 4087 input: &'i str, 4088 parser: &DummyParser, 4089 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4090 parse_ns_relative(input, parser, ParseRelative::No) 4091 } 4092 4093 fn parse_ns_relative<'i>( 4094 input: &'i str, 4095 parser: &DummyParser, 4096 parse_relative: ParseRelative, 4097 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4098 parse_ns_relative_expected(input, parser, parse_relative, None) 4099 } 4100 4101 fn parse_ns_expected<'i, 'a>( 4102 input: &'i str, 4103 parser: &DummyParser, 4104 expected: Option<&'a str>, 4105 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4106 parse_ns_relative_expected(input, parser, ParseRelative::No, expected) 4107 } 4108 4109 fn parse_ns_relative_expected<'i, 'a>( 4110 input: &'i str, 4111 parser: &DummyParser, 4112 parse_relative: ParseRelative, 4113 expected: Option<&'a str>, 4114 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> { 4115 let mut parser_input = ParserInput::new(input); 4116 let result = SelectorList::parse( 4117 parser, 4118 &mut CssParser::new(&mut parser_input), 4119 parse_relative, 4120 ); 4121 if let Ok(ref selectors) = result { 4122 // We can't assume that the serialized parsed selector will equal 4123 // the input; for example, if there is no default namespace, '*|foo' 4124 // should serialize to 'foo'. 4125 assert_eq!( 4126 selectors.to_css_string(), 4127 match expected { 4128 Some(x) => x, 4129 None => input, 4130 } 4131 ); 4132 } 4133 result 4134 } 4135 4136 fn specificity(a: u32, b: u32, c: u32) -> u32 { 4137 a << 20 | b << 10 | c 4138 } 4139 4140 #[test] 4141 fn test_empty() { 4142 let mut input = ParserInput::new(":empty"); 4143 let list = SelectorList::parse( 4144 &DummyParser::default(), 4145 &mut CssParser::new(&mut input), 4146 ParseRelative::No, 4147 ); 4148 assert!(list.is_ok()); 4149 } 4150 4151 const MATHML: &str = "http://www.w3.org/1998/Math/MathML"; 4152 const SVG: &str = "http://www.w3.org/2000/svg"; 4153 4154 #[test] 4155 fn test_parsing() { 4156 assert!(parse("").is_err()); 4157 assert!(parse(":lang(4)").is_err()); 4158 assert!(parse(":lang(en US)").is_err()); 4159 assert_eq!( 4160 parse("EeÉ"), 4161 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4162 vec![Component::LocalName(LocalName { 4163 name: DummyAtom::from("EeÉ"), 4164 lower_name: DummyAtom::from("eeÉ"), 4165 })], 4166 specificity(0, 0, 1), 4167 SelectorFlags::empty(), 4168 )])) 4169 ); 4170 assert_eq!( 4171 parse("|e"), 4172 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4173 vec![ 4174 Component::ExplicitNoNamespace, 4175 Component::LocalName(LocalName { 4176 name: DummyAtom::from("e"), 4177 lower_name: DummyAtom::from("e"), 4178 }), 4179 ], 4180 specificity(0, 0, 1), 4181 SelectorFlags::empty(), 4182 )])) 4183 ); 4184 // When the default namespace is not set, *| should be elided. 4185 // https://github.com/servo/servo/pull/17537 4186 assert_eq!( 4187 parse_expected("*|e", Some("e")), 4188 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4189 vec![Component::LocalName(LocalName { 4190 name: DummyAtom::from("e"), 4191 lower_name: DummyAtom::from("e"), 4192 })], 4193 specificity(0, 0, 1), 4194 SelectorFlags::empty(), 4195 )])) 4196 ); 4197 // When the default namespace is set, *| should _not_ be elided (as foo 4198 // is no longer equivalent to *|foo--the former is only for foo in the 4199 // default namespace). 4200 // https://github.com/servo/servo/issues/16020 4201 assert_eq!( 4202 parse_ns( 4203 "*|e", 4204 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")) 4205 ), 4206 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4207 vec![ 4208 Component::ExplicitAnyNamespace, 4209 Component::LocalName(LocalName { 4210 name: DummyAtom::from("e"), 4211 lower_name: DummyAtom::from("e"), 4212 }), 4213 ], 4214 specificity(0, 0, 1), 4215 SelectorFlags::empty(), 4216 )])) 4217 ); 4218 assert_eq!( 4219 parse("*"), 4220 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4221 vec![Component::ExplicitUniversalType], 4222 specificity(0, 0, 0), 4223 SelectorFlags::empty(), 4224 )])) 4225 ); 4226 assert_eq!( 4227 parse("|*"), 4228 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4229 vec![ 4230 Component::ExplicitNoNamespace, 4231 Component::ExplicitUniversalType, 4232 ], 4233 specificity(0, 0, 0), 4234 SelectorFlags::empty(), 4235 )])) 4236 ); 4237 assert_eq!( 4238 parse_expected("*|*", Some("*")), 4239 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4240 vec![Component::ExplicitUniversalType], 4241 specificity(0, 0, 0), 4242 SelectorFlags::empty(), 4243 )])) 4244 ); 4245 assert_eq!( 4246 parse_ns( 4247 "*|*", 4248 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")) 4249 ), 4250 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4251 vec![ 4252 Component::ExplicitAnyNamespace, 4253 Component::ExplicitUniversalType, 4254 ], 4255 specificity(0, 0, 0), 4256 SelectorFlags::empty(), 4257 )])) 4258 ); 4259 assert_eq!( 4260 parse(".foo:lang(en-US)"), 4261 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4262 vec![ 4263 Component::Class(DummyAtom::from("foo")), 4264 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())), 4265 ], 4266 specificity(0, 2, 0), 4267 SelectorFlags::empty(), 4268 )])) 4269 ); 4270 assert_eq!( 4271 parse("#bar"), 4272 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4273 vec![Component::ID(DummyAtom::from("bar"))], 4274 specificity(1, 0, 0), 4275 SelectorFlags::empty(), 4276 )])) 4277 ); 4278 assert_eq!( 4279 parse("e.foo#bar"), 4280 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4281 vec![ 4282 Component::LocalName(LocalName { 4283 name: DummyAtom::from("e"), 4284 lower_name: DummyAtom::from("e"), 4285 }), 4286 Component::Class(DummyAtom::from("foo")), 4287 Component::ID(DummyAtom::from("bar")), 4288 ], 4289 specificity(1, 1, 1), 4290 SelectorFlags::empty(), 4291 )])) 4292 ); 4293 assert_eq!( 4294 parse("e.foo #bar"), 4295 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4296 vec![ 4297 Component::LocalName(LocalName { 4298 name: DummyAtom::from("e"), 4299 lower_name: DummyAtom::from("e"), 4300 }), 4301 Component::Class(DummyAtom::from("foo")), 4302 Component::Combinator(Combinator::Descendant), 4303 Component::ID(DummyAtom::from("bar")), 4304 ], 4305 specificity(1, 1, 1), 4306 SelectorFlags::empty(), 4307 )])) 4308 ); 4309 // Default namespace does not apply to attribute selectors 4310 // https://github.com/mozilla/servo/pull/1652 4311 let mut parser = DummyParser::default(); 4312 assert_eq!( 4313 parse_ns("[Foo]", &parser), 4314 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4315 vec![Component::AttributeInNoNamespaceExists { 4316 local_name: DummyAtom::from("Foo"), 4317 local_name_lower: DummyAtom::from("foo"), 4318 }], 4319 specificity(0, 1, 0), 4320 SelectorFlags::empty(), 4321 )])) 4322 ); 4323 assert!(parse_ns("svg|circle", &parser).is_err()); 4324 parser 4325 .ns_prefixes 4326 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into())); 4327 assert_eq!( 4328 parse_ns("svg|circle", &parser), 4329 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4330 vec![ 4331 Component::Namespace(DummyAtom("svg".into()), SVG.into()), 4332 Component::LocalName(LocalName { 4333 name: DummyAtom::from("circle"), 4334 lower_name: DummyAtom::from("circle"), 4335 }), 4336 ], 4337 specificity(0, 0, 1), 4338 SelectorFlags::empty(), 4339 )])) 4340 ); 4341 assert_eq!( 4342 parse_ns("svg|*", &parser), 4343 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4344 vec![ 4345 Component::Namespace(DummyAtom("svg".into()), SVG.into()), 4346 Component::ExplicitUniversalType, 4347 ], 4348 specificity(0, 0, 0), 4349 SelectorFlags::empty(), 4350 )])) 4351 ); 4352 // Default namespace does not apply to attribute selectors 4353 // https://github.com/mozilla/servo/pull/1652 4354 // but it does apply to implicit type selectors 4355 // https://github.com/servo/rust-selectors/pull/82 4356 parser.default_ns = Some(MATHML.into()); 4357 assert_eq!( 4358 parse_ns("[Foo]", &parser), 4359 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4360 vec![ 4361 Component::DefaultNamespace(MATHML.into()), 4362 Component::AttributeInNoNamespaceExists { 4363 local_name: DummyAtom::from("Foo"), 4364 local_name_lower: DummyAtom::from("foo"), 4365 }, 4366 ], 4367 specificity(0, 1, 0), 4368 SelectorFlags::empty(), 4369 )])) 4370 ); 4371 // Default namespace does apply to type selectors 4372 assert_eq!( 4373 parse_ns("e", &parser), 4374 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4375 vec![ 4376 Component::DefaultNamespace(MATHML.into()), 4377 Component::LocalName(LocalName { 4378 name: DummyAtom::from("e"), 4379 lower_name: DummyAtom::from("e"), 4380 }), 4381 ], 4382 specificity(0, 0, 1), 4383 SelectorFlags::empty(), 4384 )])) 4385 ); 4386 assert_eq!( 4387 parse_ns("*", &parser), 4388 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4389 vec![ 4390 Component::DefaultNamespace(MATHML.into()), 4391 Component::ExplicitUniversalType, 4392 ], 4393 specificity(0, 0, 0), 4394 SelectorFlags::empty(), 4395 )])) 4396 ); 4397 assert_eq!( 4398 parse_ns("*|*", &parser), 4399 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4400 vec![ 4401 Component::ExplicitAnyNamespace, 4402 Component::ExplicitUniversalType, 4403 ], 4404 specificity(0, 0, 0), 4405 SelectorFlags::empty(), 4406 )])) 4407 ); 4408 // Default namespace applies to universal and type selectors inside :not and :matches, 4409 // but not otherwise. 4410 assert_eq!( 4411 parse_ns(":not(.cl)", &parser), 4412 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4413 vec![ 4414 Component::DefaultNamespace(MATHML.into()), 4415 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec( 4416 vec![Component::Class(DummyAtom::from("cl"))], 4417 specificity(0, 1, 0), 4418 SelectorFlags::empty(), 4419 )])), 4420 ], 4421 specificity(0, 1, 0), 4422 SelectorFlags::empty(), 4423 )])) 4424 ); 4425 assert_eq!( 4426 parse_ns(":not(*)", &parser), 4427 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4428 vec![ 4429 Component::DefaultNamespace(MATHML.into()), 4430 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec( 4431 vec![ 4432 Component::DefaultNamespace(MATHML.into()), 4433 Component::ExplicitUniversalType, 4434 ], 4435 specificity(0, 0, 0), 4436 SelectorFlags::empty(), 4437 )]),), 4438 ], 4439 specificity(0, 0, 0), 4440 SelectorFlags::empty(), 4441 )])) 4442 ); 4443 assert_eq!( 4444 parse_ns(":not(e)", &parser), 4445 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4446 vec![ 4447 Component::DefaultNamespace(MATHML.into()), 4448 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec( 4449 vec![ 4450 Component::DefaultNamespace(MATHML.into()), 4451 Component::LocalName(LocalName { 4452 name: DummyAtom::from("e"), 4453 lower_name: DummyAtom::from("e"), 4454 }), 4455 ], 4456 specificity(0, 0, 1), 4457 SelectorFlags::empty(), 4458 )])), 4459 ], 4460 specificity(0, 0, 1), 4461 SelectorFlags::empty(), 4462 )])) 4463 ); 4464 assert_eq!( 4465 parse("[attr|=\"foo\"]"), 4466 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4467 vec![Component::AttributeInNoNamespace { 4468 local_name: DummyAtom::from("attr"), 4469 operator: AttrSelectorOperator::DashMatch, 4470 value: DummyAttrValue::from("foo"), 4471 case_sensitivity: ParsedCaseSensitivity::CaseSensitive, 4472 }], 4473 specificity(0, 1, 0), 4474 SelectorFlags::empty(), 4475 )])) 4476 ); 4477 // https://github.com/mozilla/servo/issues/1723 4478 assert_eq!( 4479 parse("::before"), 4480 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4481 vec![ 4482 Component::Combinator(Combinator::PseudoElement), 4483 Component::PseudoElement(PseudoElement::Before), 4484 ], 4485 specificity(0, 0, 1), 4486 SelectorFlags::HAS_PSEUDO, 4487 )])) 4488 ); 4489 assert_eq!( 4490 parse("::before:hover"), 4491 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4492 vec![ 4493 Component::Combinator(Combinator::PseudoElement), 4494 Component::PseudoElement(PseudoElement::Before), 4495 Component::NonTSPseudoClass(PseudoClass::Hover), 4496 ], 4497 specificity(0, 1, 1), 4498 SelectorFlags::HAS_PSEUDO, 4499 )])) 4500 ); 4501 assert_eq!( 4502 parse("::before:hover:hover"), 4503 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4504 vec![ 4505 Component::Combinator(Combinator::PseudoElement), 4506 Component::PseudoElement(PseudoElement::Before), 4507 Component::NonTSPseudoClass(PseudoClass::Hover), 4508 Component::NonTSPseudoClass(PseudoClass::Hover), 4509 ], 4510 specificity(0, 2, 1), 4511 SelectorFlags::HAS_PSEUDO, 4512 )])) 4513 ); 4514 assert!(parse("::before:hover:lang(foo)").is_err()); 4515 assert!(parse("::before:hover .foo").is_err()); 4516 assert!(parse("::before .foo").is_err()); 4517 assert!(parse("::before ~ bar").is_err()); 4518 assert!(parse("::before:active").is_ok()); 4519 4520 // https://github.com/servo/servo/issues/15335 4521 assert!(parse(":: before").is_err()); 4522 assert_eq!( 4523 parse("div ::after"), 4524 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4525 vec![ 4526 Component::LocalName(LocalName { 4527 name: DummyAtom::from("div"), 4528 lower_name: DummyAtom::from("div"), 4529 }), 4530 Component::Combinator(Combinator::Descendant), 4531 Component::Combinator(Combinator::PseudoElement), 4532 Component::PseudoElement(PseudoElement::After), 4533 ], 4534 specificity(0, 0, 2), 4535 SelectorFlags::HAS_PSEUDO, 4536 )])) 4537 ); 4538 assert_eq!( 4539 parse("#d1 > .ok"), 4540 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4541 vec![ 4542 Component::ID(DummyAtom::from("d1")), 4543 Component::Combinator(Combinator::Child), 4544 Component::Class(DummyAtom::from("ok")), 4545 ], 4546 specificity(1, 1, 0), 4547 SelectorFlags::empty(), 4548 )])) 4549 ); 4550 parser.default_ns = None; 4551 assert!(parse(":not(#provel.old)").is_ok()); 4552 assert!(parse(":not(#provel > old)").is_ok()); 4553 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok()); 4554 // https://github.com/servo/servo/issues/16017 4555 assert_eq!( 4556 parse_ns(":not(*)", &parser), 4557 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4558 vec![Component::Negation(SelectorList::from_vec(vec![ 4559 Selector::from_vec( 4560 vec![Component::ExplicitUniversalType], 4561 specificity(0, 0, 0), 4562 SelectorFlags::empty(), 4563 ) 4564 ]))], 4565 specificity(0, 0, 0), 4566 SelectorFlags::empty(), 4567 )])) 4568 ); 4569 assert_eq!( 4570 parse_ns(":not(|*)", &parser), 4571 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4572 vec![Component::Negation(SelectorList::from_vec(vec![ 4573 Selector::from_vec( 4574 vec![ 4575 Component::ExplicitNoNamespace, 4576 Component::ExplicitUniversalType, 4577 ], 4578 specificity(0, 0, 0), 4579 SelectorFlags::empty(), 4580 ) 4581 ]))], 4582 specificity(0, 0, 0), 4583 SelectorFlags::empty(), 4584 )])) 4585 ); 4586 // *| should be elided if there is no default namespace. 4587 // https://github.com/servo/servo/pull/17537 4588 assert_eq!( 4589 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")), 4590 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4591 vec![Component::Negation(SelectorList::from_vec(vec![ 4592 Selector::from_vec( 4593 vec![Component::ExplicitUniversalType], 4594 specificity(0, 0, 0), 4595 SelectorFlags::empty(), 4596 ) 4597 ]))], 4598 specificity(0, 0, 0), 4599 SelectorFlags::empty(), 4600 )])) 4601 ); 4602 4603 assert!(parse("::highlight(foo)").is_ok()); 4604 4605 assert!(parse("::slotted()").is_err()); 4606 assert!(parse("::slotted(div)").is_ok()); 4607 assert!(parse("::slotted(div).foo").is_err()); 4608 assert!(parse("::slotted(div + bar)").is_err()); 4609 assert!(parse("::slotted(div) + foo").is_err()); 4610 4611 assert!(parse("::part()").is_err()); 4612 assert!(parse("::part(42)").is_err()); 4613 assert!(parse("::part(foo bar)").is_ok()); 4614 assert!(parse("::part(foo):hover").is_ok()); 4615 assert!(parse("::part(foo) + bar").is_err()); 4616 4617 assert!(parse("div ::slotted(div)").is_ok()); 4618 assert!(parse("div + slot::slotted(div)").is_ok()); 4619 assert!(parse("div + slot::slotted(div.foo)").is_ok()); 4620 assert!(parse("slot::slotted(div,foo)::first-line").is_err()); 4621 assert!(parse("::slotted(div)::before").is_ok()); 4622 assert!(parse("slot::slotted(div,foo)").is_err()); 4623 4624 assert!(parse("foo:where()").is_ok()); 4625 assert!(parse("foo:where(div, foo, .bar baz)").is_ok()); 4626 assert!(parse("foo:where(::before)").is_ok()); 4627 } 4628 4629 #[test] 4630 fn parent_selector() { 4631 assert!(parse("foo &").is_ok()); 4632 assert_eq!( 4633 parse("#foo &.bar"), 4634 Ok(SelectorList::from_vec(vec![Selector::from_vec( 4635 vec![ 4636 Component::ID(DummyAtom::from("foo")), 4637 Component::Combinator(Combinator::Descendant), 4638 Component::ParentSelector, 4639 Component::Class(DummyAtom::from("bar")), 4640 ], 4641 specificity(1, 1, 0), 4642 SelectorFlags::HAS_PARENT 4643 )])) 4644 ); 4645 4646 let parent = parse(".bar, div .baz").unwrap(); 4647 let child = parse("#foo &.bar").unwrap(); 4648 assert_eq!( 4649 child.replace_parent_selector(&parent), 4650 parse("#foo :is(.bar, div .baz).bar").unwrap() 4651 ); 4652 4653 let has_child = parse("#foo:has(&.bar)").unwrap(); 4654 assert_eq!( 4655 has_child.replace_parent_selector(&parent), 4656 parse("#foo:has(:is(.bar, div .baz).bar)").unwrap() 4657 ); 4658 4659 let child = 4660 parse_relative_expected("#foo", ParseRelative::ForNesting, Some("& #foo")).unwrap(); 4661 assert_eq!( 4662 child.replace_parent_selector(&parent), 4663 parse(":is(.bar, div .baz) #foo").unwrap() 4664 ); 4665 4666 let child = 4667 parse_relative_expected("+ #foo", ParseRelative::ForNesting, Some("& + #foo")).unwrap(); 4668 assert_eq!(child, parse("& + #foo").unwrap()); 4669 } 4670 4671 #[test] 4672 fn test_pseudo_iter() { 4673 let list = parse("q::before").unwrap(); 4674 let selector = &list.slice()[0]; 4675 assert!(!selector.is_universal()); 4676 let mut iter = selector.iter(); 4677 assert_eq!( 4678 iter.next(), 4679 Some(&Component::PseudoElement(PseudoElement::Before)) 4680 ); 4681 assert_eq!(iter.next(), None); 4682 let combinator = iter.next_sequence(); 4683 assert_eq!(combinator, Some(Combinator::PseudoElement)); 4684 assert_eq!( 4685 iter.next(), 4686 Some(&Component::LocalName(LocalName { 4687 name: DummyAtom::from("q"), 4688 lower_name: DummyAtom::from("q"), 4689 })) 4690 ); 4691 assert_eq!(iter.next(), None); 4692 assert_eq!(iter.next_sequence(), None); 4693 } 4694 4695 #[test] 4696 fn test_pseudo_before_marker() { 4697 let list = parse("::before::marker").unwrap(); 4698 let selector = &list.slice()[0]; 4699 let mut iter = selector.iter(); 4700 assert_eq!( 4701 iter.next(), 4702 Some(&Component::PseudoElement(PseudoElement::Marker)) 4703 ); 4704 assert_eq!(iter.next(), None); 4705 let combinator = iter.next_sequence(); 4706 assert_eq!(combinator, Some(Combinator::PseudoElement)); 4707 assert_eq!( 4708 iter.next(), 4709 Some(&Component::PseudoElement(PseudoElement::Before)) 4710 ); 4711 assert_eq!(iter.next(), None); 4712 let combinator = iter.next_sequence(); 4713 assert_eq!(combinator, Some(Combinator::PseudoElement)); 4714 assert_eq!(iter.next(), None); 4715 assert_eq!(iter.next_sequence(), None); 4716 } 4717 4718 #[test] 4719 fn test_pseudo_duplicate_before_after_or_marker() { 4720 assert!(parse("::before::before").is_err()); 4721 assert!(parse("::after::after").is_err()); 4722 assert!(parse("::marker::marker").is_err()); 4723 } 4724 4725 #[test] 4726 fn test_pseudo_on_element_backed_pseudo() { 4727 let list = parse("::details-content::before").unwrap(); 4728 let selector = &list.slice()[0]; 4729 let mut iter = selector.iter(); 4730 assert_eq!( 4731 iter.next(), 4732 Some(&Component::PseudoElement(PseudoElement::Before)) 4733 ); 4734 assert_eq!(iter.next(), None); 4735 let combinator = iter.next_sequence(); 4736 assert_eq!(combinator, Some(Combinator::PseudoElement)); 4737 assert_eq!( 4738 iter.next(), 4739 Some(&Component::PseudoElement(PseudoElement::DetailsContent)) 4740 ); 4741 assert_eq!(iter.next(), None); 4742 let combinator = iter.next_sequence(); 4743 assert_eq!(combinator, Some(Combinator::PseudoElement)); 4744 assert_eq!(iter.next(), None); 4745 assert_eq!(iter.next_sequence(), None); 4746 } 4747 4748 #[test] 4749 fn test_universal() { 4750 let list = parse_ns( 4751 "*|*::before", 4752 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")), 4753 ) 4754 .unwrap(); 4755 let selector = &list.slice()[0]; 4756 assert!(selector.is_universal()); 4757 } 4758 4759 #[test] 4760 fn test_empty_pseudo_iter() { 4761 let list = parse("::before").unwrap(); 4762 let selector = &list.slice()[0]; 4763 assert!(selector.is_universal()); 4764 let mut iter = selector.iter(); 4765 assert_eq!( 4766 iter.next(), 4767 Some(&Component::PseudoElement(PseudoElement::Before)) 4768 ); 4769 assert_eq!(iter.next(), None); 4770 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement)); 4771 assert_eq!(iter.next(), None); 4772 assert_eq!(iter.next_sequence(), None); 4773 } 4774 4775 #[test] 4776 fn test_parse_implicit_scope() { 4777 assert_eq!( 4778 parse_relative_expected(".foo", ParseRelative::ForScope, None).unwrap(), 4779 SelectorList::from_vec(vec![Selector::from_vec( 4780 vec![ 4781 Component::ImplicitScope, 4782 Component::Combinator(Combinator::Descendant), 4783 Component::Class(DummyAtom::from("foo")), 4784 ], 4785 specificity(0, 1, 0), 4786 SelectorFlags::HAS_SCOPE, 4787 )]) 4788 ); 4789 4790 assert_eq!( 4791 parse_relative_expected(":scope .foo", ParseRelative::ForScope, None).unwrap(), 4792 SelectorList::from_vec(vec![Selector::from_vec( 4793 vec![ 4794 Component::Scope, 4795 Component::Combinator(Combinator::Descendant), 4796 Component::Class(DummyAtom::from("foo")), 4797 ], 4798 specificity(0, 2, 0), 4799 SelectorFlags::HAS_SCOPE 4800 )]) 4801 ); 4802 4803 assert_eq!( 4804 parse_relative_expected("> .foo", ParseRelative::ForScope, Some("> .foo")).unwrap(), 4805 SelectorList::from_vec(vec![Selector::from_vec( 4806 vec![ 4807 Component::ImplicitScope, 4808 Component::Combinator(Combinator::Child), 4809 Component::Class(DummyAtom::from("foo")), 4810 ], 4811 specificity(0, 1, 0), 4812 SelectorFlags::HAS_SCOPE 4813 )]) 4814 ); 4815 4816 assert_eq!( 4817 parse_relative_expected(".foo :scope > .bar", ParseRelative::ForScope, None).unwrap(), 4818 SelectorList::from_vec(vec![Selector::from_vec( 4819 vec![ 4820 Component::Class(DummyAtom::from("foo")), 4821 Component::Combinator(Combinator::Descendant), 4822 Component::Scope, 4823 Component::Combinator(Combinator::Child), 4824 Component::Class(DummyAtom::from("bar")), 4825 ], 4826 specificity(0, 3, 0), 4827 SelectorFlags::HAS_SCOPE 4828 )]) 4829 ); 4830 } 4831 4832 struct TestVisitor { 4833 seen: Vec<String>, 4834 } 4835 4836 impl SelectorVisitor for TestVisitor { 4837 type Impl = DummySelectorImpl; 4838 4839 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool { 4840 let mut dest = String::new(); 4841 s.to_css(&mut dest).unwrap(); 4842 self.seen.push(dest); 4843 true 4844 } 4845 } 4846 4847 #[test] 4848 fn visitor() { 4849 let mut test_visitor = TestVisitor { seen: vec![] }; 4850 parse(":not(:hover) ~ label").unwrap().slice()[0].visit(&mut test_visitor); 4851 assert!(test_visitor.seen.contains(&":hover".into())); 4852 4853 let mut test_visitor = TestVisitor { seen: vec![] }; 4854 parse("::before:hover").unwrap().slice()[0].visit(&mut test_visitor); 4855 assert!(test_visitor.seen.contains(&":hover".into())); 4856 } 4857 }