Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5
use crate::attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
6
use crate::attr::{NamespaceConstraint, ParsedAttrSelectorOperation};
7
use crate::attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE};
8
use crate::bloom::BLOOM_HASH_MASK;
9
use crate::builder::{SelectorBuilder, SelectorFlags, SpecificityAndFlags};
10
use crate::context::QuirksMode;
11
use crate::sink::Push;
12
pub use crate::visitor::{SelectorVisitor, Visit};
13
use cssparser::{parse_nth, serialize_identifier};
14
use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
15
use cssparser::{CowRcStr, Delimiter, SourceLocation};
16
use cssparser::{CssStringWriter, Parser as CssParser, ToCss, Token};
17
use precomputed_hash::PrecomputedHash;
18
use servo_arc::ThinArc;
19
use smallvec::SmallVec;
20
use std::borrow::{Borrow, Cow};
21
use std::fmt::{self, Debug, Display, Write};
22
use std::iter::Rev;
23
use std::slice;
24
use thin_slice::ThinBoxedSlice;
25
26
/// A trait that represents a pseudo-element.
27
pub trait PseudoElement: Sized + ToCss {
28
/// The `SelectorImpl` this pseudo-element is used for.
29
type Impl: SelectorImpl;
30
31
/// Whether the pseudo-element supports a given state selector to the right
32
/// of it.
33
fn accepts_state_pseudo_classes(&self) -> bool {
34
false
35
}
36
37
/// Whether this pseudo-element is valid after a ::slotted(..) pseudo.
38
fn valid_after_slotted(&self) -> bool {
39
false
40
}
41
}
42
43
/// A trait that represents a pseudo-class.
44
pub trait NonTSPseudoClass: Sized + ToCss {
45
/// The `SelectorImpl` this pseudo-element is used for.
46
type Impl: SelectorImpl;
47
48
/// Whether this pseudo-class is :active or :hover.
49
fn is_active_or_hover(&self) -> bool;
50
51
/// Whether this pseudo-class belongs to:
52
///
54
fn is_user_action_state(&self) -> bool;
55
}
56
57
/// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
58
/// Cow::Owned if `s` had to be converted into ASCII lowercase.
59
fn to_ascii_lowercase(s: &str) -> Cow<str> {
60
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
61
let mut string = s.to_owned();
62
string[first_uppercase..].make_ascii_lowercase();
63
string.into()
64
} else {
65
s.into()
66
}
67
}
68
69
bitflags! {
70
/// Flags that indicate at which point of parsing a selector are we.
71
struct SelectorParsingState: u8 {
72
/// Whether we're inside a negation. If we're inside a negation, we're
73
/// not allowed to add another negation or such, for example.
74
const INSIDE_NEGATION = 1 << 0;
75
/// Whether we've parsed a ::slotted() pseudo-element already.
76
///
77
/// If so, then we can only parse a subset of pseudo-elements, and
78
/// whatever comes after them if so.
79
const AFTER_SLOTTED = 1 << 1;
80
/// Whether we've parsed a ::part() pseudo-element already.
81
///
82
/// If so, then we can only parse a subset of pseudo-elements, and
83
/// whatever comes after them if so.
84
const AFTER_PART = 1 << 2;
85
/// Whether we've parsed a pseudo-element (as in, an
86
/// `Impl::PseudoElement` thus not accounting for `::slotted` or
87
/// `::part`) already.
88
///
89
/// If so, then other pseudo-elements and most other selectors are
90
/// disallowed.
91
const AFTER_PSEUDO_ELEMENT = 1 << 3;
92
/// Whether we've parsed a non-stateful pseudo-element (again, as-in
93
/// `Impl::PseudoElement`) already. If so, then other pseudo-classes are
94
/// disallowed. If this flag is set, `AFTER_PSEUDO_ELEMENT` must be set
95
/// as well.
96
const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
97
/// Whether we are after any of the pseudo-like things.
98
const AFTER_PSEUDO = Self::AFTER_PART.bits | Self::AFTER_SLOTTED.bits | Self::AFTER_PSEUDO_ELEMENT.bits;
99
}
100
}
101
102
impl SelectorParsingState {
103
#[inline]
104
fn allows_functional_pseudo_classes(self) -> bool {
105
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
106
}
107
108
#[inline]
109
fn allows_slotted(self) -> bool {
110
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
111
}
112
113
// TODO(emilio): Should we allow other ::part()s after ::part()?
114
//
116
#[inline]
117
fn allows_part(self) -> bool {
118
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
119
}
120
121
#[inline]
122
fn allows_non_functional_pseudo_classes(self) -> bool {
123
!self.intersects(
124
SelectorParsingState::AFTER_SLOTTED |
125
SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT,
126
)
127
}
128
129
#[inline]
130
fn allows_tree_structural_pseudo_classes(self) -> bool {
131
!self.intersects(SelectorParsingState::AFTER_PSEUDO)
132
}
133
}
134
135
pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>;
136
137
#[derive(Clone, Debug, PartialEq)]
138
pub enum SelectorParseErrorKind<'i> {
139
PseudoElementInComplexSelector,
140
NoQualifiedNameInAttributeSelector(Token<'i>),
141
EmptySelector,
142
DanglingCombinator,
143
NonSimpleSelectorInNegation,
144
NonCompoundSelector,
145
NonPseudoElementAfterSlotted,
146
InvalidPseudoElementAfterSlotted,
147
InvalidState,
148
UnexpectedTokenInAttributeSelector(Token<'i>),
149
PseudoElementExpectedColon(Token<'i>),
150
PseudoElementExpectedIdent(Token<'i>),
151
NoIdentForPseudo(Token<'i>),
152
UnsupportedPseudoClassOrElement(CowRcStr<'i>),
153
UnexpectedIdent(CowRcStr<'i>),
154
ExpectedNamespace(CowRcStr<'i>),
155
ExpectedBarInAttr(Token<'i>),
156
BadValueInAttr(Token<'i>),
157
InvalidQualNameInAttr(Token<'i>),
158
ExplicitNamespaceUnexpectedToken(Token<'i>),
159
ClassNeedsIdent(Token<'i>),
160
EmptyNegation,
161
}
162
163
macro_rules! with_all_bounds {
164
(
165
[ $( $InSelector: tt )* ]
166
[ $( $CommonBounds: tt )* ]
167
[ $( $FromStr: tt )* ]
168
) => {
169
/// This trait allows to define the parser implementation in regards
170
/// of pseudo-classes/elements
171
///
172
/// NB: We need Clone so that we can derive(Clone) on struct with that
173
/// are parameterized on SelectorImpl. See
175
pub trait SelectorImpl: Clone + Debug + Sized + 'static {
176
type ExtraMatchingData: Sized + Default + 'static;
177
type AttrValue: $($InSelector)*;
178
type Identifier: $($InSelector)*;
179
type ClassName: $($InSelector)*;
180
type PartName: $($InSelector)*;
181
type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
182
type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
183
type NamespacePrefix: $($InSelector)* + Default;
184
type BorrowedNamespaceUrl: ?Sized + Eq;
185
type BorrowedLocalName: ?Sized + Eq;
186
187
/// non tree-structural pseudo-classes
189
type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass<Impl = Self>;
190
191
/// pseudo-elements
192
type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
193
}
194
}
195
}
196
197
macro_rules! with_bounds {
198
( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
199
with_all_bounds! {
200
[$($CommonBounds)* + $($FromStr)* + Display]
201
[$($CommonBounds)*]
202
[$($FromStr)*]
203
}
204
}
205
}
206
207
with_bounds! {
208
[Clone + Eq]
209
[for<'a> From<&'a str>]
210
}
211
212
pub trait Parser<'i> {
213
type Impl: SelectorImpl;
214
type Error: 'i + From<SelectorParseErrorKind<'i>>;
215
216
/// Whether to parse the `::slotted()` pseudo-element.
217
fn parse_slotted(&self) -> bool {
218
false
219
}
220
221
/// Whether to parse the `::part()` pseudo-element.
222
fn parse_part(&self) -> bool {
223
false
224
}
225
226
/// Whether to parse the `:host` pseudo-class.
227
fn parse_host(&self) -> bool {
228
false
229
}
230
231
/// This function can return an "Err" pseudo-element in order to support CSS2.1
232
/// pseudo-elements.
233
fn parse_non_ts_pseudo_class(
234
&self,
235
location: SourceLocation,
236
name: CowRcStr<'i>,
237
) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
238
Err(
239
location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
240
name,
241
)),
242
)
243
}
244
245
fn parse_non_ts_functional_pseudo_class<'t>(
246
&self,
247
name: CowRcStr<'i>,
248
arguments: &mut CssParser<'i, 't>,
249
) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
250
Err(
251
arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
252
name,
253
)),
254
)
255
}
256
257
fn parse_pseudo_element(
258
&self,
259
location: SourceLocation,
260
name: CowRcStr<'i>,
261
) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
262
Err(
263
location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
264
name,
265
)),
266
)
267
}
268
269
fn parse_functional_pseudo_element<'t>(
270
&self,
271
name: CowRcStr<'i>,
272
arguments: &mut CssParser<'i, 't>,
273
) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
274
Err(
275
arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
276
name,
277
)),
278
)
279
}
280
281
fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
282
None
283
}
284
285
fn namespace_for_prefix(
286
&self,
287
_prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix,
288
) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
289
None
290
}
291
}
292
293
#[derive(Clone, Debug, Eq, PartialEq, ToShmem)]
294
#[shmem(no_bounds)]
295
pub struct SelectorList<Impl: SelectorImpl>(
296
#[shmem(field_bound)] pub SmallVec<[Selector<Impl>; 1]>,
297
);
298
299
impl<Impl: SelectorImpl> SelectorList<Impl> {
300
/// Parse a comma-separated list of Selectors.
302
///
303
/// Return the Selectors or Err if there is an invalid selector.
304
pub fn parse<'i, 't, P>(
305
parser: &P,
306
input: &mut CssParser<'i, 't>,
307
) -> Result<Self, ParseError<'i, P::Error>>
308
where
309
P: Parser<'i, Impl = Impl>,
310
{
311
let mut values = SmallVec::new();
312
loop {
313
values.push(
314
input
315
.parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?,
316
);
317
match input.next() {
318
Err(_) => return Ok(SelectorList(values)),
319
Ok(&Token::Comma) => continue,
320
Ok(_) => unreachable!(),
321
}
322
}
323
}
324
325
/// Creates a SelectorList from a Vec of selectors. Used in tests.
326
pub fn from_vec(v: Vec<Selector<Impl>>) -> Self {
327
SelectorList(SmallVec::from_vec(v))
328
}
329
}
330
331
/// Parses one compound selector suitable for nested stuff like ::-moz-any, etc.
332
fn parse_inner_compound_selector<'i, 't, P, Impl>(
333
parser: &P,
334
input: &mut CssParser<'i, 't>,
335
) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
336
where
337
P: Parser<'i, Impl = Impl>,
338
Impl: SelectorImpl,
339
{
340
let location = input.current_source_location();
341
let selector = parse_selector(parser, input)?;
342
343
// Ensure they're actually all compound selectors without pseudo-elements.
344
if selector.has_pseudo_element() {
345
return Err(
346
location.new_custom_error(SelectorParseErrorKind::PseudoElementInComplexSelector)
347
);
348
}
349
350
if selector.iter_raw_match_order().any(|s| s.is_combinator()) {
351
return Err(location.new_custom_error(SelectorParseErrorKind::NonCompoundSelector));
352
}
353
354
Ok(selector)
355
}
356
357
/// Parse a comma separated list of compound selectors.
358
pub fn parse_compound_selector_list<'i, 't, P, Impl>(
359
parser: &P,
360
input: &mut CssParser<'i, 't>,
361
) -> Result<Box<[Selector<Impl>]>, ParseError<'i, P::Error>>
362
where
363
P: Parser<'i, Impl = Impl>,
364
Impl: SelectorImpl,
365
{
366
input
367
.parse_comma_separated(|input| parse_inner_compound_selector(parser, input))
368
.map(|selectors| selectors.into_boxed_slice())
369
}
370
371
/// Ancestor hashes for the bloom filter. We precompute these and store them
372
/// inline with selectors to optimize cache performance during matching.
373
/// This matters a lot.
374
///
375
/// We use 4 hashes, which is copied from Gecko, who copied it from WebKit.
376
/// Note that increasing the number of hashes here will adversely affect the
377
/// cache hit when fast-rejecting long lists of Rules with inline hashes.
378
///
379
/// Because the bloom filter only uses the bottom 24 bits of the hash, we pack
380
/// the fourth hash into the upper bits of the first three hashes in order to
381
/// shrink Rule (whose size matters a lot). This scheme minimizes the runtime
382
/// overhead of the packing for the first three hashes (we just need to mask
383
/// off the upper bits) at the expense of making the fourth somewhat more
384
/// complicated to assemble, because we often bail out before checking all the
385
/// hashes.
386
#[derive(Clone, Debug, Eq, PartialEq)]
387
pub struct AncestorHashes {
388
pub packed_hashes: [u32; 3],
389
}
390
391
impl AncestorHashes {
392
pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self
393
where
394
Impl::Identifier: PrecomputedHash,
395
Impl::ClassName: PrecomputedHash,
396
Impl::LocalName: PrecomputedHash,
397
Impl::NamespaceUrl: PrecomputedHash,
398
{
399
Self::from_iter(selector.iter(), quirks_mode)
400
}
401
402
fn from_iter<Impl: SelectorImpl>(iter: SelectorIter<Impl>, quirks_mode: QuirksMode) -> Self
403
where
404
Impl::Identifier: PrecomputedHash,
405
Impl::ClassName: PrecomputedHash,
406
Impl::LocalName: PrecomputedHash,
407
Impl::NamespaceUrl: PrecomputedHash,
408
{
409
// Compute ancestor hashes for the bloom filter.
410
let mut hashes = [0u32; 4];
411
let mut hash_iter = AncestorIter::new(iter).filter_map(|x| x.ancestor_hash(quirks_mode));
412
for i in 0..4 {
413
hashes[i] = match hash_iter.next() {
414
Some(x) => x & BLOOM_HASH_MASK,
415
None => break,
416
}
417
}
418
419
// Now, pack the fourth hash (if it exists) into the upper byte of each of
420
// the other three hashes.
421
let fourth = hashes[3];
422
if fourth != 0 {
423
hashes[0] |= (fourth & 0x000000ff) << 24;
424
hashes[1] |= (fourth & 0x0000ff00) << 16;
425
hashes[2] |= (fourth & 0x00ff0000) << 8;
426
}
427
428
AncestorHashes {
429
packed_hashes: [hashes[0], hashes[1], hashes[2]],
430
}
431
}
432
433
/// Returns the fourth hash, reassembled from parts.
434
pub fn fourth_hash(&self) -> u32 {
435
((self.packed_hashes[0] & 0xff000000) >> 24) |
436
((self.packed_hashes[1] & 0xff000000) >> 16) |
437
((self.packed_hashes[2] & 0xff000000) >> 8)
438
}
439
}
440
441
impl<Impl: SelectorImpl> Visit for Selector<Impl>
442
where
443
Impl::NonTSPseudoClass: Visit<Impl = Impl>,
444
{
445
type Impl = Impl;
446
447
fn visit<V>(&self, visitor: &mut V) -> bool
448
where
449
V: SelectorVisitor<Impl = Impl>,
450
{
451
let mut current = self.iter();
452
let mut combinator = None;
453
loop {
454
if !visitor.visit_complex_selector(combinator) {
455
return false;
456
}
457
458
for selector in &mut current {
459
if !selector.visit(visitor) {
460
return false;
461
}
462
}
463
464
combinator = current.next_sequence();
465
if combinator.is_none() {
466
break;
467
}
468
}
469
470
true
471
}
472
}
473
474
impl<Impl: SelectorImpl> Visit for Component<Impl>
475
where
476
Impl::NonTSPseudoClass: Visit<Impl = Impl>,
477
{
478
type Impl = Impl;
479
480
fn visit<V>(&self, visitor: &mut V) -> bool
481
where
482
V: SelectorVisitor<Impl = Impl>,
483
{
484
use self::Component::*;
485
if !visitor.visit_simple_selector(self) {
486
return false;
487
}
488
489
match *self {
490
Slotted(ref selector) => {
491
if !selector.visit(visitor) {
492
return false;
493
}
494
},
495
Host(Some(ref selector)) => {
496
if !selector.visit(visitor) {
497
return false;
498
}
499
},
500
Negation(ref negated) => {
501
for component in negated.iter() {
502
if !component.visit(visitor) {
503
return false;
504
}
505
}
506
},
507
508
AttributeInNoNamespaceExists {
509
ref local_name,
510
ref local_name_lower,
511
} => {
512
if !visitor.visit_attribute_selector(
513
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
514
local_name,
515
local_name_lower,
516
) {
517
return false;
518
}
519
},
520
AttributeInNoNamespace {
521
ref local_name,
522
never_matches,
523
..
524
} if !never_matches => {
525
if !visitor.visit_attribute_selector(
526
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
527
local_name,
528
local_name,
529
) {
530
return false;
531
}
532
},
533
AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
534
let empty_string;
535
let namespace = match attr_selector.namespace() {
536
Some(ns) => ns,
537
None => {
538
empty_string = crate::parser::namespace_empty_string::<Impl>();
539
NamespaceConstraint::Specific(&empty_string)
540
},
541
};
542
if !visitor.visit_attribute_selector(
543
&namespace,
544
&attr_selector.local_name,
545
&attr_selector.local_name_lower,
546
) {
547
return false;
548
}
549
},
550
551
NonTSPseudoClass(ref pseudo_class) => {
552
if !pseudo_class.visit(visitor) {
553
return false;
554
}
555
},
556
_ => {},
557
}
558
559
true
560
}
561
}
562
563
pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
564
// Rust type’s default, not default namespace
565
Impl::NamespaceUrl::default()
566
}
567
568
/// A Selector stores a sequence of simple selectors and combinators. The
569
/// iterator classes allow callers to iterate at either the raw sequence level or
570
/// at the level of sequences of simple selectors separated by combinators. Most
571
/// callers want the higher-level iterator.
572
///
573
/// We store compound selectors internally right-to-left (in matching order).
574
/// Additionally, we invert the order of top-level compound selectors so that
575
/// each one matches left-to-right. This is because matching namespace, local name,
576
/// id, and class are all relatively cheap, whereas matching pseudo-classes might
577
/// be expensive (depending on the pseudo-class). Since authors tend to put the
578
/// pseudo-classes on the right, it's faster to start matching on the left.
579
///
580
/// This reordering doesn't change the semantics of selector matching, and we
581
/// handle it in to_css to make it invisible to serialization.
582
#[derive(Clone, Eq, PartialEq, ToShmem)]
583
#[shmem(no_bounds)]
584
pub struct Selector<Impl: SelectorImpl>(
585
#[shmem(field_bound)] ThinArc<SpecificityAndFlags, Component<Impl>>,
586
);
587
588
impl<Impl: SelectorImpl> Selector<Impl> {
589
#[inline]
590
pub fn specificity(&self) -> u32 {
591
self.0.header.header.specificity()
592
}
593
594
#[inline]
595
pub fn has_pseudo_element(&self) -> bool {
596
self.0.header.header.has_pseudo_element()
597
}
598
599
#[inline]
600
pub fn is_slotted(&self) -> bool {
601
self.0.header.header.is_slotted()
602
}
603
604
#[inline]
605
pub fn is_part(&self) -> bool {
606
self.0.header.header.is_part()
607
}
608
609
#[inline]
610
pub fn parts(&self) -> Option<&[Impl::PartName]> {
611
if !self.is_part() {
612
return None;
613
}
614
615
let mut iter = self.iter();
616
if self.has_pseudo_element() {
617
// Skip the pseudo-element.
618
for _ in &mut iter {}
619
620
let combinator = iter.next_sequence()?;
621
debug_assert_eq!(combinator, Combinator::PseudoElement);
622
}
623
624
for component in iter {
625
if let Component::Part(ref part) = *component {
626
return Some(part);
627
}
628
}
629
630
debug_assert!(false, "is_part() lied somehow?");
631
None
632
}
633
634
#[inline]
635
pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
636
if !self.has_pseudo_element() {
637
return None;
638
}
639
640
for component in self.iter() {
641
if let Component::PseudoElement(ref pseudo) = *component {
642
return Some(pseudo);
643
}
644
}
645
646
debug_assert!(false, "has_pseudo_element lied!");
647
None
648
}
649
650
/// Whether this selector (pseudo-element part excluded) matches every element.
651
///
652
/// Used for "pre-computed" pseudo-elements in components/style/stylist.rs
653
#[inline]
654
pub fn is_universal(&self) -> bool {
655
self.iter_raw_match_order().all(|c| {
656
matches!(
657
*c,
658
Component::ExplicitUniversalType |
659
Component::ExplicitAnyNamespace |
660
Component::Combinator(Combinator::PseudoElement) |
661
Component::PseudoElement(..)
662
)
663
})
664
}
665
666
/// Returns an iterator over this selector in matching order (right-to-left).
667
/// When a combinator is reached, the iterator will return None, and
668
/// next_sequence() may be called to continue to the next sequence.
669
#[inline]
670
pub fn iter(&self) -> SelectorIter<Impl> {
671
SelectorIter {
672
iter: self.iter_raw_match_order(),
673
next_combinator: None,
674
}
675
}
676
677
/// Whether this selector is a featureless :host selector, with no
678
/// combinators to the left, and optionally has a pseudo-element to the
679
/// right.
680
#[inline]
681
pub fn is_featureless_host_selector_or_pseudo_element(&self) -> bool {
682
let mut iter = self.iter();
683
if !self.has_pseudo_element() {
684
return iter.is_featureless_host_selector();
685
}
686
687
// Skip the pseudo-element.
688
for _ in &mut iter {}
689
690
match iter.next_sequence() {
691
None => return false,
692
Some(combinator) => {
693
debug_assert_eq!(combinator, Combinator::PseudoElement);
694
},
695
}
696
697
iter.is_featureless_host_selector()
698
}
699
700
/// Returns an iterator over this selector in matching order (right-to-left),
701
/// skipping the rightmost |offset| Components.
702
#[inline]
703
pub fn iter_from(&self, offset: usize) -> SelectorIter<Impl> {
704
let iter = self.0.slice[offset..].iter();
705
SelectorIter {
706
iter: iter,
707
next_combinator: None,
708
}
709
}
710
711
/// Returns the combinator at index `index` (zero-indexed from the right),
712
/// or panics if the component is not a combinator.
713
#[inline]
714
pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
715
match self.0.slice[index] {
716
Component::Combinator(c) => c,
717
ref other => panic!(
718
"Not a combinator: {:?}, {:?}, index: {}",
719
other, self, index
720
),
721
}
722
}
723
724
/// Returns an iterator over the entire sequence of simple selectors and
725
/// combinators, in matching order (from right to left).
726
#[inline]
727
pub fn iter_raw_match_order(&self) -> slice::Iter<Component<Impl>> {
728
self.0.slice.iter()
729
}
730
731
/// Returns the combinator at index `index` (zero-indexed from the left),
732
/// or panics if the component is not a combinator.
733
#[inline]
734
pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
735
match self.0.slice[self.len() - index - 1] {
736
Component::Combinator(c) => c,
737
ref other => panic!(
738
"Not a combinator: {:?}, {:?}, index: {}",
739
other, self, index
740
),
741
}
742
}
743
744
/// Returns an iterator over the sequence of simple selectors and
745
/// combinators, in parse order (from left to right), starting from
746
/// `offset`.
747
#[inline]
748
pub fn iter_raw_parse_order_from(&self, offset: usize) -> Rev<slice::Iter<Component<Impl>>> {
749
self.0.slice[..self.len() - offset].iter().rev()
750
}
751
752
/// Creates a Selector from a vec of Components, specified in parse order. Used in tests.
753
#[allow(unused)]
754
pub(crate) fn from_vec(
755
vec: Vec<Component<Impl>>,
756
specificity: u32,
757
flags: SelectorFlags,
758
) -> Self {
759
let mut builder = SelectorBuilder::default();
760
for component in vec.into_iter() {
761
if let Some(combinator) = component.as_combinator() {
762
builder.push_combinator(combinator);
763
} else {
764
builder.push_simple_selector(component);
765
}
766
}
767
let spec = SpecificityAndFlags { specificity, flags };
768
Selector(builder.build_with_specificity_and_flags(spec))
769
}
770
771
/// Returns count of simple selectors and combinators in the Selector.
772
#[inline]
773
pub fn len(&self) -> usize {
774
self.0.slice.len()
775
}
776
777
/// Returns the address on the heap of the ThinArc for memory reporting.
778
pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
779
self.0.heap_ptr()
780
}
781
}
782
783
#[derive(Clone)]
784
pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
785
iter: slice::Iter<'a, Component<Impl>>,
786
next_combinator: Option<Combinator>,
787
}
788
789
impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
790
/// Prepares this iterator to point to the next sequence to the left,
791
/// returning the combinator if the sequence was found.
792
#[inline]
793
pub fn next_sequence(&mut self) -> Option<Combinator> {
794
self.next_combinator.take()
795
}
796
797
/// Whether this selector is a featureless host selector, with no
798
/// combinators to the left.
799
#[inline]
800
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
801
self.selector_length() > 0 &&
802
self.all(|component| matches!(*component, Component::Host(..))) &&
803
self.next_sequence().is_none()
804
}
805
806
/// Returns remaining count of the simple selectors and combinators in the Selector.
807
#[inline]
808
pub fn selector_length(&self) -> usize {
809
self.iter.len()
810
}
811
}
812
813
impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
814
type Item = &'a Component<Impl>;
815
816
#[inline]
817
fn next(&mut self) -> Option<Self::Item> {
818
debug_assert!(
819
self.next_combinator.is_none(),
820
"You should call next_sequence!"
821
);
822
match *self.iter.next()? {
823
Component::Combinator(c) => {
824
self.next_combinator = Some(c);
825
None
826
},
827
ref x => Some(x),
828
}
829
}
830
}
831
832
impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
833
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
834
let iter = self.iter.clone().rev();
835
for component in iter {
836
component.to_css(f)?
837
}
838
Ok(())
839
}
840
}
841
842
/// An iterator over all simple selectors belonging to ancestors.
843
struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
844
impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
845
/// Creates an AncestorIter. The passed-in iterator is assumed to point to
846
/// the beginning of the child sequence, which will be skipped.
847
fn new(inner: SelectorIter<'a, Impl>) -> Self {
848
let mut result = AncestorIter(inner);
849
result.skip_until_ancestor();
850
result
851
}
852
853
/// Skips a sequence of simple selectors and all subsequent sequences until
854
/// a non-pseudo-element ancestor combinator is reached.
855
fn skip_until_ancestor(&mut self) {
856
loop {
857
while self.0.next().is_some() {}
858
// If this is ever changed to stop at the "pseudo-element"
859
// combinator, we will need to fix the way we compute hashes for
860
// revalidation selectors.
861
if self.0.next_sequence().map_or(true, |x| {
862
matches!(x, Combinator::Child | Combinator::Descendant)
863
}) {
864
break;
865
}
866
}
867
}
868
}
869
870
impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
871
type Item = &'a Component<Impl>;
872
fn next(&mut self) -> Option<Self::Item> {
873
// Grab the next simple selector in the sequence if available.
874
let next = self.0.next();
875
if next.is_some() {
876
return next;
877
}
878
879
// See if there are more sequences. If so, skip any non-ancestor sequences.
880
if let Some(combinator) = self.0.next_sequence() {
881
if !matches!(combinator, Combinator::Child | Combinator::Descendant) {
882
self.skip_until_ancestor();
883
}
884
}
885
886
self.0.next()
887
}
888
}
889
890
#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
891
pub enum Combinator {
892
Child, // >
893
Descendant, // space
894
NextSibling, // +
895
LaterSibling, // ~
896
/// A dummy combinator we use to the left of pseudo-elements.
897
///
898
/// It serializes as the empty string, and acts effectively as a child
899
/// combinator in most cases. If we ever actually start using a child
900
/// combinator for this, we will need to fix up the way hashes are computed
901
/// for revalidation selectors.
902
PseudoElement,
903
/// Another combinator used for ::slotted(), which represent the jump from
904
/// a node to its assigned slot.
905
SlotAssignment,
906
/// Another combinator used for `::part()`, which represents the jump from
907
/// the part to the containing shadow host.
908
Part,
909
}
910
911
impl Combinator {
912
/// Returns true if this combinator is a child or descendant combinator.
913
#[inline]
914
pub fn is_ancestor(&self) -> bool {
915
matches!(
916
*self,
917
Combinator::Child |
918
Combinator::Descendant |
919
Combinator::PseudoElement |
920
Combinator::SlotAssignment
921
)
922
}
923
924
/// Returns true if this combinator is a pseudo-element combinator.
925
#[inline]
926
pub fn is_pseudo_element(&self) -> bool {
927
matches!(*self, Combinator::PseudoElement)
928
}
929
930
/// Returns true if this combinator is a next- or later-sibling combinator.
931
#[inline]
932
pub fn is_sibling(&self) -> bool {
933
matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
934
}
935
}
936
937
/// A CSS simple selector or combinator. We store both in the same enum for
938
/// optimal packing and cache performance, see [1].
939
///
941
#[derive(Clone, Eq, PartialEq, ToShmem)]
942
#[shmem(no_bounds)]
943
pub enum Component<Impl: SelectorImpl> {
944
Combinator(Combinator),
945
946
ExplicitAnyNamespace,
947
ExplicitNoNamespace,
948
DefaultNamespace(#[shmem(field_bound)] Impl::NamespaceUrl),
949
Namespace(
950
#[shmem(field_bound)] Impl::NamespacePrefix,
951
#[shmem(field_bound)] Impl::NamespaceUrl,
952
),
953
954
ExplicitUniversalType,
955
LocalName(LocalName<Impl>),
956
957
ID(#[shmem(field_bound)] Impl::Identifier),
958
Class(#[shmem(field_bound)] Impl::ClassName),
959
960
AttributeInNoNamespaceExists {
961
#[shmem(field_bound)]
962
local_name: Impl::LocalName,
963
local_name_lower: Impl::LocalName,
964
},
965
// Used only when local_name is already lowercase.
966
AttributeInNoNamespace {
967
local_name: Impl::LocalName,
968
operator: AttrSelectorOperator,
969
#[shmem(field_bound)]
970
value: Impl::AttrValue,
971
case_sensitivity: ParsedCaseSensitivity,
972
never_matches: bool,
973
},
974
// Use a Box in the less common cases with more data to keep size_of::<Component>() small.
975
AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
976
977
/// Pseudo-classes
978
///
979
/// CSS3 Negation only takes a simple simple selector, but we still need to
980
/// treat it as a compound selector because it might be a type selector
981
/// which we represent as a namespace and a localname.
982
///
983
/// Note: if/when we upgrade this to CSS4, which supports combinators, we
984
/// need to think about how this should interact with
985
/// visit_complex_selector, and what the consumers of those APIs should do
986
/// about the presence of combinators in negation.
987
Negation(ThinBoxedSlice<Component<Impl>>),
988
FirstChild,
989
LastChild,
990
OnlyChild,
991
Root,
992
Empty,
993
Scope,
994
NthChild(i32, i32),
995
NthLastChild(i32, i32),
996
NthOfType(i32, i32),
997
NthLastOfType(i32, i32),
998
FirstOfType,
999
LastOfType,
1000
OnlyOfType,
1001
NonTSPseudoClass(#[shmem(field_bound)] Impl::NonTSPseudoClass),
1002
/// The ::slotted() pseudo-element:
1003
///
1005
///
1006
/// The selector here is a compound selector, that is, no combinators.
1007
///
1008
/// NOTE(emilio): This should support a list of selectors, but as of this
1009
/// writing no other browser does, and that allows them to put ::slotted()
1010
/// in the rule hash, so we do that too.
1011
///
1013
Slotted(Selector<Impl>),
1014
/// The `::part` pseudo-element.
1016
Part(#[shmem(field_bound)] Box<[Impl::PartName]>),
1017
/// The `:host` pseudo-class:
1018
///
1020
///
1021
/// NOTE(emilio): This should support a list of selectors, but as of this
1022
/// writing no other browser does, and that allows them to put :host()
1023
/// in the rule hash, so we do that too.
1024
///
1026
Host(Option<Selector<Impl>>),
1027
PseudoElement(#[shmem(field_bound)] Impl::PseudoElement),
1028
}
1029
1030
impl<Impl: SelectorImpl> Component<Impl> {
1031
/// Compute the ancestor hash to check against the bloom filter.
1032
fn ancestor_hash(&self, quirks_mode: QuirksMode) -> Option<u32>
1033
where
1034
Impl::Identifier: PrecomputedHash,
1035
Impl::ClassName: PrecomputedHash,
1036
Impl::LocalName: PrecomputedHash,
1037
Impl::NamespaceUrl: PrecomputedHash,
1038
{
1039
match *self {
1040
Component::LocalName(LocalName {
1041
ref name,
1042
ref lower_name,
1043
}) => {
1044
// Only insert the local-name into the filter if it's all
1045
// lowercase. Otherwise we would need to test both hashes, and
1046
// our data structures aren't really set up for that.
1047
if name == lower_name {
1048
Some(name.precomputed_hash())
1049
} else {
1050
None
1051
}
1052
},
1053
Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => {
1054
Some(url.precomputed_hash())
1055
},
1056
// In quirks mode, class and id selectors should match
1057
// case-insensitively, so just avoid inserting them into the filter.
1058
Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => {
1059
Some(id.precomputed_hash())
1060
},
1061
Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
1062
Some(class.precomputed_hash())
1063
},
1064
_ => None,
1065
}
1066
}
1067
1068
/// Returns true if this is a combinator.
1069
pub fn is_combinator(&self) -> bool {
1070
matches!(*self, Component::Combinator(_))
1071
}
1072
1073
/// Returns the value as a combinator if applicable, None otherwise.
1074
pub fn as_combinator(&self) -> Option<Combinator> {
1075
match *self {
1076
Component::Combinator(c) => Some(c),
1077
_ => None,
1078
}
1079
}
1080
}
1081
1082
#[derive(Clone, Eq, PartialEq, ToShmem)]
1083
#[shmem(no_bounds)]
1084
pub struct LocalName<Impl: SelectorImpl> {
1085
#[shmem(field_bound)]
1086
pub name: Impl::LocalName,
1087
pub lower_name: Impl::LocalName,
1088
}
1089
1090
impl<Impl: SelectorImpl> Debug for Selector<Impl> {
1091
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1092
f.write_str("Selector(")?;
1093
self.to_css(f)?;
1094
write!(f, ", specificity = 0x{:x})", self.specificity())
1095
}
1096
}
1097
1098
impl<Impl: SelectorImpl> Debug for Component<Impl> {
1099
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1100
self.to_css(f)
1101
}
1102
}
1103
impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
1104
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1105
self.to_css(f)
1106
}
1107
}
1108
impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
1109
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1110
self.to_css(f)
1111
}
1112
}
1113
1114
impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
1115
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1116
where
1117
W: fmt::Write,
1118
{
1119
let mut iter = self.0.iter();
1120
let first = iter
1121
.next()
1122
.expect("Empty SelectorList, should contain at least one selector");
1123
first.to_css(dest)?;
1124
for selector in iter {
1125
dest.write_str(", ")?;
1126
selector.to_css(dest)?;
1127
}
1128
Ok(())
1129
}
1130
}
1131
1132
impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
1133
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1134
where
1135
W: fmt::Write,
1136
{
1137
// Compound selectors invert the order of their contents, so we need to
1138
// undo that during serialization.
1139
//
1140
// This two-iterator strategy involves walking over the selector twice.
1141
// We could do something more clever, but selector serialization probably
1142
// isn't hot enough to justify it, and the stringification likely
1143
// dominates anyway.
1144
//
1145
// NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(),
1146
// which we need for |split|. So we split by combinators on a match-order
1147
// sequence and then reverse.
1148
1149
let mut combinators = self
1150
.iter_raw_match_order()
1151
.rev()
1152
.filter_map(|x| x.as_combinator());
1153
let compound_selectors = self
1154
.iter_raw_match_order()
1155
.as_slice()
1156
.split(|x| x.is_combinator())
1157
.rev();
1158
1159
let mut combinators_exhausted = false;
1160
for compound in compound_selectors {
1161
debug_assert!(!combinators_exhausted);
1162
1164
if compound.is_empty() {
1165
continue;
1166
}
1167
1168
// 1. If there is only one simple selector in the compound selectors
1169
// which is a universal selector, append the result of
1170
// serializing the universal selector to s.
1171
//
1172
// Check if `!compound.empty()` first--this can happen if we have
1173
// something like `... > ::before`, because we store `>` and `::`
1174
// both as combinators internally.
1175
//
1176
// If we are in this case, after we have serialized the universal
1177
// selector, we skip Step 2 and continue with the algorithm.
1178
let (can_elide_namespace, first_non_namespace) = match compound[0] {
1179
Component::ExplicitAnyNamespace |
1180
Component::ExplicitNoNamespace |
1181
Component::Namespace(..) => (false, 1),
1182
Component::DefaultNamespace(..) => (true, 1),
1183
_ => (true, 0),
1184
};
1185
let mut perform_step_2 = true;
1186
let next_combinator = combinators.next();
1187
if first_non_namespace == compound.len() - 1 {
1188
match (next_combinator, &compound[first_non_namespace]) {
1189
// We have to be careful here, because if there is a
1190
// pseudo element "combinator" there isn't really just
1191
// the one simple selector. Technically this compound
1192
// selector contains the pseudo element selector as well
1193
// -- Combinator::PseudoElement, just like
1194
// Combinator::SlotAssignment, don't exist in the
1195
// spec.
1196
(Some(Combinator::PseudoElement), _) |
1197
(Some(Combinator::SlotAssignment), _) => (),
1198
(_, &Component::ExplicitUniversalType) => {
1199
// Iterate over everything so we serialize the namespace
1200
// too.
1201
for simple in compound.iter() {
1202
simple.to_css(dest)?;
1203
}
1204
// Skip step 2, which is an "otherwise".
1205
perform_step_2 = false;
1206
},
1207
_ => (),
1208
}
1209
}
1210
1211
// 2. Otherwise, for each simple selector in the compound selectors
1212
// that is not a universal selector of which the namespace prefix
1213
// maps to a namespace that is not the default namespace
1214
// serialize the simple selector and append the result to s.
1215
//
1217
// proposing to change this to match up with the behavior asserted
1218
// in cssom/serialize-namespaced-type-selectors.html, which the
1219
// following code tries to match.
1220
if perform_step_2 {
1221
for simple in compound.iter() {
1222
if let Component::ExplicitUniversalType = *simple {
1223
// Can't have a namespace followed by a pseudo-element
1224
// selector followed by a universal selector in the same
1225
// compound selector, so we don't have to worry about the
1226
// real namespace being in a different `compound`.
1227
if can_elide_namespace {
1228
continue;
1229
}
1230
}
1231
simple.to_css(dest)?;
1232
}
1233
}
1234
1235
// 3. If this is not the last part of the chain of the selector
1236
// append a single SPACE (U+0020), followed by the combinator
1237
// ">", "+", "~", ">>", "||", as appropriate, followed by another
1238
// single SPACE (U+0020) if the combinator was not whitespace, to
1239
// s.
1240
match next_combinator {
1241
Some(c) => c.to_css(dest)?,
1242
None => combinators_exhausted = true,
1243
};
1244
1245
// 4. If this is the last part of the chain of the selector and
1246
// there is a pseudo-element, append "::" followed by the name of
1247
// the pseudo-element, to s.
1248
//
1249
// (we handle this above)
1250
}
1251
1252
Ok(())
1253
}
1254
}
1255
1256
impl ToCss for Combinator {
1257
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1258
where
1259
W: fmt::Write,
1260
{
1261
match *self {
1262
Combinator::Child => dest.write_str(" > "),
1263
Combinator::Descendant => dest.write_str(" "),
1264
Combinator::NextSibling => dest.write_str(" + "),
1265
Combinator::LaterSibling => dest.write_str(" ~ "),
1266
Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => Ok(()),
1267
}
1268
}
1269
}
1270
1271
impl<Impl: SelectorImpl> ToCss for Component<Impl> {
1272
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1273
where
1274
W: fmt::Write,
1275
{
1276
use self::Component::*;
1277
1278
/// Serialize <an+b> values (part of the CSS Syntax spec, but currently only used here).
1280
fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result
1281
where
1282
W: fmt::Write,
1283
{
1284
match (a, b) {
1285
(0, 0) => dest.write_char('0'),
1286
1287
(1, 0) => dest.write_char('n'),
1288
(-1, 0) => dest.write_str("-n"),
1289
(_, 0) => write!(dest, "{}n", a),
1290
1291
(0, _) => write!(dest, "{}", b),
1292
(1, _) => write!(dest, "n{:+}", b),
1293
(-1, _) => write!(dest, "-n{:+}", b),
1294
(_, _) => write!(dest, "{}n{:+}", a, b),
1295
}
1296
}
1297
1298
match *self {
1299
Combinator(ref c) => c.to_css(dest),
1300
Slotted(ref selector) => {
1301
dest.write_str("::slotted(")?;
1302
selector.to_css(dest)?;
1303
dest.write_char(')')
1304
},
1305
Part(ref part_names) => {
1306
dest.write_str("::part(")?;
1307
for (i, name) in part_names.iter().enumerate() {
1308
if i != 0 {
1309
dest.write_char(' ')?;
1310
}
1311
display_to_css_identifier(name, dest)?;
1312
}
1313
dest.write_char(')')
1314
},
1315
PseudoElement(ref p) => p.to_css(dest),
1316
ID(ref s) => {
1317
dest.write_char('#')?;
1318
display_to_css_identifier(s, dest)
1319
},
1320
Class(ref s) => {
1321
dest.write_char('.')?;
1322
display_to_css_identifier(s, dest)
1323
},
1324
LocalName(ref s) => s.to_css(dest),
1325
ExplicitUniversalType => dest.write_char('*'),
1326
1327
DefaultNamespace(_) => Ok(()),
1328
ExplicitNoNamespace => dest.write_char('|'),
1329
ExplicitAnyNamespace => dest.write_str("*|"),
1330
Namespace(ref prefix, _) => {
1331
display_to_css_identifier(prefix, dest)?;
1332
dest.write_char('|')
1333
},
1334
1335
AttributeInNoNamespaceExists { ref local_name, .. } => {
1336
dest.write_char('[')?;
1337
display_to_css_identifier(local_name, dest)?;
1338
dest.write_char(']')
1339
},
1340
AttributeInNoNamespace {
1341
ref local_name,
1342
operator,
1343
ref value,
1344
case_sensitivity,
1345
..
1346
} => {
1347
dest.write_char('[')?;
1348
display_to_css_identifier(local_name, dest)?;
1349
operator.to_css(dest)?;
1350
dest.write_char('"')?;
1351
write!(CssStringWriter::new(dest), "{}", value)?;
1352
dest.write_char('"')?;
1353
match case_sensitivity {
1354
ParsedCaseSensitivity::CaseSensitive |
1355
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
1356
ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1357
ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1358
}
1359
dest.write_char(']')
1360
},
1361
AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
1362
1363
// Pseudo-classes
1364
Negation(ref arg) => {
1365
dest.write_str(":not(")?;
1366
for component in arg.iter() {
1367
component.to_css(dest)?;
1368
}
1369
dest.write_str(")")
1370
},
1371
1372
FirstChild => dest.write_str(":first-child"),
1373
LastChild => dest.write_str(":last-child"),
1374
OnlyChild => dest.write_str(":only-child"),
1375
Root => dest.write_str(":root"),
1376
Empty => dest.write_str(":empty"),
1377
Scope => dest.write_str(":scope"),
1378
Host(ref selector) => {
1379
dest.write_str(":host")?;
1380
if let Some(ref selector) = *selector {
1381
dest.write_char('(')?;
1382
selector.to_css(dest)?;
1383
dest.write_char(')')?;
1384
}
1385
Ok(())
1386
},
1387
FirstOfType => dest.write_str(":first-of-type"),
1388
LastOfType => dest.write_str(":last-of-type"),
1389
OnlyOfType => dest.write_str(":only-of-type"),
1390
NthChild(a, b) | NthLastChild(a, b) | NthOfType(a, b) | NthLastOfType(a, b) => {
1391
match *self {
1392
NthChild(_, _) => dest.write_str(":nth-child(")?,
1393
NthLastChild(_, _) => dest.write_str(":nth-last-child(")?,
1394
NthOfType(_, _) => dest.write_str(":nth-of-type(")?,
1395
NthLastOfType(_, _) => dest.write_str(":nth-last-of-type(")?,
1396
_ => unreachable!(),
1397
}
1398
write_affine(dest, a, b)?;
1399
dest.write_char(')')
1400
},
1401
NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
1402
}
1403
}
1404
}
1405
1406
impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
1407
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1408
where
1409
W: fmt::Write,
1410
{
1411
dest.write_char('[')?;
1412
match self.namespace {
1413
Some(NamespaceConstraint::Specific((ref prefix, _))) => {
1414
display_to_css_identifier(prefix, dest)?;
1415
dest.write_char('|')?
1416
},
1417
Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
1418
None => {},
1419
}
1420
display_to_css_identifier(&self.local_name, dest)?;
1421
match self.operation {
1422
ParsedAttrSelectorOperation::Exists => {},
1423
ParsedAttrSelectorOperation::WithValue {
1424
operator,
1425
case_sensitivity,
1426
ref expected_value,
1427
} => {
1428
operator.to_css(dest)?;
1429
dest.write_char('"')?;
1430
write!(CssStringWriter::new(dest), "{}", expected_value)?;
1431
dest.write_char('"')?;
1432
match case_sensitivity {
1433
ParsedCaseSensitivity::CaseSensitive |
1434
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
1435
ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1436
ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1437
}
1438
},
1439
}
1440
dest.write_char(']')
1441
}
1442
}
1443
1444
impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
1445
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1446
where
1447
W: fmt::Write,
1448
{
1449
display_to_css_identifier(&self.name, dest)
1450
}
1451
}
1452
1453
/// Serialize the output of Display as a CSS identifier
1454
fn display_to_css_identifier<T: Display, W: fmt::Write>(x: &T, dest: &mut W) -> fmt::Result {
1455
// FIXME(SimonSapin): it is possible to avoid this heap allocation
1456
// by creating a stream adapter like cssparser::CssStringWriter
1457
// that holds and writes to `&mut W` and itself implements `fmt::Write`.
1458
//
1459
// I haven’t done this yet because it would require somewhat complex and fragile state machine
1460
// to support in `fmt::Write::write_char` cases that,
1461
// in `serialize_identifier` (which has the full value as a `&str` slice),
1462
// can be expressed as
1463
// `string.starts_with("--")`, `string == "-"`, `string.starts_with("-")`, etc.
1464
//
1465
// And I don’t even know if this would be a performance win: jemalloc is good at what it does
1466
// and the state machine might be slower than `serialize_identifier` as currently written.
1467
let string = x.to_string();
1468
1469
serialize_identifier(&string, dest)
1470
}
1471
1472
/// Build up a Selector.
1473
/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
1474
///
1475
/// `Err` means invalid selector.
1476
fn parse_selector<'i, 't, P, Impl>(
1477
parser: &P,
1478
input: &mut CssParser<'i, 't>,
1479
) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
1480
where
1481
P: Parser<'i, Impl = Impl>,
1482
Impl: SelectorImpl,
1483
{
1484
let mut builder = SelectorBuilder::default();
1485
1486
let mut has_pseudo_element = false;
1487
let mut slotted = false;
1488
let mut part = false;
1489
'outer_loop: loop {
1490
// Parse a sequence of simple selectors.
1491
let state = match parse_compound_selector(parser, input, &mut builder)? {
1492
Some(state) => state,
1493
None => {
1494
return Err(input.new_custom_error(if builder.has_combinators() {
1495
SelectorParseErrorKind::DanglingCombinator
1496
} else {
1497
SelectorParseErrorKind::EmptySelector
1498
}));
1499
},
1500
};
1501
1502
if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
1503
has_pseudo_element = state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
1504
slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
1505
part = state.intersects(SelectorParsingState::AFTER_PART);
1506
debug_assert!(has_pseudo_element || slotted || part);
1507
break;
1508
}
1509
1510
// Parse a combinator.
1511
let combinator;
1512
let mut any_whitespace = false;
1513
loop {
1514
let before_this_token = input.state();
1515
match input.next_including_whitespace() {
1516
Err(_e) => break 'outer_loop,
1517
Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
1518
Ok(&Token::Delim('>')) => {
1519
combinator = Combinator::Child;
1520
break;
1521
},
1522
Ok(&Token::Delim('+')) => {
1523
combinator = Combinator::NextSibling;
1524
break;
1525
},
1526
Ok(&Token::Delim('~')) => {
1527
combinator = Combinator::LaterSibling;
1528
break;
1529
},
1530
Ok(_) => {
1531
input.reset(&before_this_token);
1532
if any_whitespace {
1533
combinator = Combinator::Descendant;
1534
break;
1535
} else {
1536
break 'outer_loop;
1537
}
1538
},
1539
}
1540
}
1541
builder.push_combinator(combinator);
1542
}
1543
1544
Ok(Selector(builder.build(has_pseudo_element, slotted, part)))
1545
}
1546
1547
impl<Impl: SelectorImpl> Selector<Impl> {
1548
/// Parse a selector, without any pseudo-element.
1549
#[inline]
1550
pub fn parse<'i, 't, P>(
1551
parser: &P,
1552
input: &mut CssParser<'i, 't>,
1553
) -> Result<Self, ParseError<'i, P::Error>>
1554
where
1555
P: Parser<'i, Impl = Impl>,
1556
{
1557
parse_selector(parser, input)
1558
}
1559
}
1560
1561
/// * `Err(())`: Invalid selector, abort
1562
/// * `Ok(false)`: Not a type selector, could be something else. `input` was not consumed.
1563
/// * `Ok(true)`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
1564
fn parse_type_selector<'i, 't, P, Impl, S>(
1565
parser: &P,
1566
input: &mut CssParser<'i, 't>,
1567
sink: &mut S,
1568
) -> Result<bool, ParseError<'i, P::Error>>
1569
where
1570
P: Parser<'i, Impl = Impl>,
1571
Impl: SelectorImpl,
1572
S: Push<Component<Impl>>,
1573
{
1574
match parse_qualified_name(parser, input, /* in_attr_selector = */ false) {
1575
Err(ParseError {
1576
kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
1577
..
1578
}) |
1579
Ok(OptionalQName::None(_)) => Ok(false),
1580
Ok(OptionalQName::Some(namespace, local_name)) => {
1581
match namespace {
1582
QNamePrefix::ImplicitAnyNamespace => {},
1583
QNamePrefix::ImplicitDefaultNamespace(url) => {
1584
sink.push(Component::DefaultNamespace(url))
1585
},
1586
QNamePrefix::ExplicitNamespace(prefix, url) => {
1587
sink.push(match parser.default_namespace() {
1588
Some(ref default_url) if url == *default_url => {
1589
Component::DefaultNamespace(url)
1590
},
1591
_ => Component::Namespace(prefix, url),
1592
})
1593
},
1594
QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
1595
QNamePrefix::ExplicitAnyNamespace => {
1596
match parser.default_namespace() {
1597
// Element type selectors that have no namespace
1598
// component (no namespace separator) represent elements
1599
// without regard to the element's namespace (equivalent
1600
// to "*|") unless a default namespace has been declared
1601
// for namespaced selectors (e.g. in CSS, in the style
1602
// sheet). If a default namespace has been declared,
1603
// such selectors will represent only elements in the
1604
// default namespace.
1605
// -- Selectors § 6.1.1
1606
// So we'll have this act the same as the
1607
// QNamePrefix::ImplicitAnyNamespace case.
1608
None => {},
1609
Some(_) => sink.push(Component::ExplicitAnyNamespace),
1610
}
1611
},
1612
QNamePrefix::ImplicitNoNamespace => {
1613
unreachable!() // Not returned with in_attr_selector = false
1614
},
1615
}
1616
match local_name {
1617
Some(name) => sink.push(Component::LocalName(LocalName {
1618
lower_name: to_ascii_lowercase(&name).as_ref().into(),
1619
name: name.as_ref().into(),
1620
})),
1621
None => sink.push(Component::ExplicitUniversalType),
1622
}
1623
Ok(true)
1624
},
1625
Err(e) => Err(e),
1626
}
1627
}
1628
1629
#[derive(Debug)]
1630
enum SimpleSelectorParseResult<Impl: SelectorImpl> {
1631
SimpleSelector(Component<Impl>),
1632
PseudoElement(Impl::PseudoElement),
1633
SlottedPseudo(Selector<Impl>),
1634
PartPseudo(Box<[Impl::PartName]>),
1635
}
1636
1637
#[derive(Debug)]
1638
enum QNamePrefix<Impl: SelectorImpl> {
1639
ImplicitNoNamespace, // `foo` in attr selectors
1640
ImplicitAnyNamespace, // `foo` in type selectors, without a default ns
1641
ImplicitDefaultNamespace(Impl::NamespaceUrl), // `foo` in type selectors, with a default ns
1642
ExplicitNoNamespace, // `|foo`
1643
ExplicitAnyNamespace, // `*|foo`
1644
ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo`
1645
}
1646
1647
enum OptionalQName<'i, Impl: SelectorImpl> {
1648
Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
1649
None(Token<'i>),
1650
}
1651
1652
/// * `Err(())`: Invalid selector, abort
1653
/// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed,
1654
/// but the token is still returned.
1655
/// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector
1656
fn parse_qualified_name<'i, 't, P, Impl>(
1657
parser: &P,
1658
input: &mut CssParser<'i, 't>,
1659
in_attr_selector: bool,
1660
) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
1661
where
1662
P: Parser<'i, Impl = Impl>,
1663
Impl: SelectorImpl,
1664
{
1665
let default_namespace = |local_name| {
1666
let namespace = match parser.default_namespace() {
1667
Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
1668
None => QNamePrefix::ImplicitAnyNamespace,
1669
};
1670
Ok(OptionalQName::Some(namespace, local_name))
1671
};
1672
1673
let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
1674
let location = input.current_source_location();
1675
match input.next_including_whitespace() {
1676
Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
1677
Ok(&Token::Ident(ref local_name)) => {
1678
Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
1679
},
1680
Ok(t) if in_attr_selector => {
1681
let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
1682
Err(location.new_custom_error(e))
1683
},
1684
Ok(t) => Err(location.new_custom_error(
1685
SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()),
1686
)),
1687
Err(e) => Err(e.into()),
1688
}
1689
};
1690
1691
let start = input.state();
1692
// FIXME: remove clone() when lifetimes are non-lexical
1693
match input.next_including_whitespace().map(|t| t.clone()) {
1694
Ok(Token::Ident(value)) => {
1695
let after_ident = input.state();
1696
match input.next_including_whitespace() {
1697
Ok(&Token::Delim('|')) => {
1698
let prefix = value.as_ref().into();
1699
let result = parser.namespace_for_prefix(&prefix);
1700
let url = result.ok_or(
1701
after_ident
1702
.source_location()
1703
.new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
1704
)?;
1705
explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
1706
},
1707
_ => {
1708
input.reset(&after_ident);
1709
if in_attr_selector {
1710
Ok(OptionalQName::Some(
1711
QNamePrefix::ImplicitNoNamespace,
1712
Some(value),
1713
))
1714
} else {
1715
default_namespace(Some(value))
1716
}
1717
},
1718
}
1719
},
1720
Ok(Token::Delim('*')) => {
1721
let after_star = input.state();
1722
// FIXME: remove clone() when lifetimes are non-lexical
1723
match input.next_including_whitespace().map(|t| t.clone()) {
1724
Ok(Token::Delim('|')) => {
1725
explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
1726
},
1727
result => {
1728
input.reset(&after_star);
1729
if in_attr_selector {
1730
match result {
1731
Ok(t) => Err(after_star
1732
.source_location()
1733
.new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t))),
1734
Err(e) => Err(e.into()),
1735
}
1736
} else {
1737
default_namespace(None)
1738
}
1739
},
1740
}
1741
},
1742
Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
1743
Ok(t) => {
1744
input.reset(&start);
1745
Ok(OptionalQName::None(t))
1746
},
1747
Err(e) => {
1748
input.reset(&start);
1749
Err(e.into())
1750
},
1751
}
1752
}
1753
1754
fn parse_attribute_selector<'i, 't, P, Impl>(
1755
parser: &P,
1756
input: &mut CssParser<'i, 't>,
1757
) -> Result<Component<Impl>, ParseError<'i, P::Error>>
1758
where
1759
P: Parser<'i, Impl = Impl>,
1760
Impl: SelectorImpl,
1761
{
1762
let namespace;
1763
let local_name;
1764
1765
input.skip_whitespace();
1766
1767
match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
1768
OptionalQName::None(t) => {
1769
return Err(input.new_custom_error(
1770
SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
1771
));
1772
},
1773
OptionalQName::Some(_, None) => unreachable!(),
1774
OptionalQName::Some(ns, Some(ln)) => {
1775
local_name = ln;
1776
namespace = match ns {
1777
QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
1778
QNamePrefix::ExplicitNamespace(prefix, url) => {
1779
Some(NamespaceConstraint::Specific((prefix, url)))
1780
},
1781
QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
1782
QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
1783
unreachable!() // Not returned with in_attr_selector = true
1784
},
1785
}
1786
},
1787
}
1788
1789
let location = input.current_source_location();
1790
let operator = match input.next() {
1791
// [foo]
1792
Err(_) => {
1793
let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
1794
let local_name = local_name.as_ref().into();
1795
if let Some(namespace) = namespace {
1796
return Ok(Component::AttributeOther(Box::new(
1797
AttrSelectorWithOptionalNamespace {
1798
namespace: Some(namespace),
1799
local_name: local_name,
1800
local_name_lower: local_name_lower,
1801
operation: ParsedAttrSelectorOperation::Exists,
1802
never_matches: false,
1803
},
1804
)));
1805
} else {
1806
return Ok(Component::AttributeInNoNamespaceExists {
1807
local_name: local_name,
1808
local_name_lower: local_name_lower,
1809
});
1810
}
1811
},
1812
1813
// [foo=bar]
1814
Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
1815
// [foo~=bar]
1816
Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
1817
// [foo|=bar]
1818
Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
1819
// [foo^=bar]
1820
Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
1821
// [foo*=bar]
1822
Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
1823
// [foo$=bar]
1824
Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
1825
Ok(t) => {
1826
return Err(location.new_custom_error(
1827
SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()),
1828
));
1829
},
1830
};
1831
1832
let value = match input.expect_ident_or_string() {
1833
Ok(t) => t.clone(),
1834
Err(BasicParseError {
1835
kind: BasicParseErrorKind::UnexpectedToken(t),
1836
location,
1837
}) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
1838
Err(e) => return Err(e.into()),
1839
};
1840
let never_matches = match operator {
1841
AttrSelectorOperator::Equal | AttrSelectorOperator::DashMatch => false,
1842
1843
AttrSelectorOperator::Includes => value.is_empty() || value.contains(SELECTOR_WHITESPACE),
1844
1845
AttrSelectorOperator::Prefix |
1846
AttrSelectorOperator::Substring |
1847
AttrSelectorOperator::Suffix => value.is_empty(),
1848
};
1849
1850
let attribute_flags = parse_attribute_flags(input)?;
1851
1852
let value = value.as_ref().into();
1853
let local_name_lower;
1854
let local_name_is_ascii_lowercase;
1855
let case_sensitivity;
1856
{
1857
let local_name_lower_cow = to_ascii_lowercase(&local_name);
1858
case_sensitivity =
1859
attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
1860
local_name_lower = local_name_lower_cow.as_ref().into();
1861
local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
1862
}
1863
let local_name = local_name.as_ref().into();
1864
if namespace.is_some() || !local_name_is_ascii_lowercase {
1865
Ok(Component::AttributeOther(Box::new(
1866
AttrSelectorWithOptionalNamespace {
1867
namespace,
1868
local_name,
1869
local_name_lower,
1870
never_matches,
1871
operation: ParsedAttrSelectorOperation::WithValue {
1872
operator: operator,
1873
case_sensitivity: case_sensitivity,
1874
expected_value: value,
1875
},
1876
},
1877
)))
1878
} else {
1879
Ok(Component::AttributeInNoNamespace {
1880
local_name: local_name,
1881
operator: operator,
1882
value: value,
1883
case_sensitivity: case_sensitivity,
1884
never_matches: never_matches,
1885
})
1886
}
1887
}
1888
1889
/// An attribute selector can have 's' or 'i' as flags, or no flags at all.
1890
enum AttributeFlags {
1891
// Matching should be case-sensitive ('s' flag).
1892
CaseSensitive,
1893
// Matching should be case-insensitive ('i' flag).
1894
AsciiCaseInsensitive,
1895
// No flags. Matching behavior depends on the name of the attribute.
1896
CaseSensitivityDependsOnName,
1897
}
1898
1899
impl AttributeFlags {
1900
fn to_case_sensitivity(self, local_name: &str, have_namespace: bool) -> ParsedCaseSensitivity {
1901
match self {
1902
AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
1903
AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
1904
AttributeFlags::CaseSensitivityDependsOnName => {
1905
if !have_namespace &&
1906
include!(concat!(
1907
env!("OUT_DIR"),
1908
"/ascii_case_insensitive_html_attributes.rs"
1909
))
1910
.contains(local_name)
1911
{
1912
ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
1913
} else {
1914
ParsedCaseSensitivity::CaseSensitive
1915
}
1916
},
1917
}
1918
}
1919
}
1920
1921
fn parse_attribute_flags<'i, 't>(
1922
input: &mut CssParser<'i, 't>,
1923
) -> Result<AttributeFlags, BasicParseError<'i>> {
1924
let location = input.current_source_location();
1925
let token = match input.next() {
1926
Ok(t) => t,
1927
Err(..) => {
1928
// Selectors spec says language-defined; HTML says it depends on the
1929
// exact attribute name.
1930
return Ok(AttributeFlags::CaseSensitivityDependsOnName);
1931
},
1932
};
1933
1934
let ident = match *token {
1935
Token::Ident(ref i) => i,
1936
ref other => return Err(location.new_basic_unexpected_token_error(other.clone())),
1937
};
1938
1939
Ok(match_ignore_ascii_case! {
1940
ident,
1941
"i" => AttributeFlags::AsciiCaseInsensitive,
1942
"s" => AttributeFlags::CaseSensitive,
1943
_ => return Err(location.new_basic_unexpected_token_error(token.clone())),
1944
})
1945
}
1946
1947
/// Level 3: Parse **one** simple_selector. (Though we might insert a second
1948
/// implied "<defaultns>|*" type selector.)
1949
fn parse_negation<'i, 't, P, Impl>(
1950
parser: &P,
1951
input: &mut CssParser<'i, 't>,
1952
) -> Result<Component<Impl>, ParseError<'i, P::Error>>
1953
where
1954
P: Parser<'i, Impl = Impl>,
1955
Impl: SelectorImpl,
1956
{
1957
// We use a sequence because a type selector may be represented as two Components.
1958
let mut sequence = SmallVec::<[Component<Impl>; 2]>::new();
1959
1960
input.skip_whitespace();
1961
1962
// Get exactly one simple selector. The parse logic in the caller will verify
1963
// that there are no trailing tokens after we're done.
1964
let is_type_sel = match parse_type_selector(parser, input, &mut sequence) {
1965
Ok(result) => result,
1966
Err(ParseError {
1967
kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
1968
..
1969
}) => return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation)),
1970
Err(e) => return Err(e.into()),
1971
};
1972
if !is_type_sel {
1973
match parse_one_simple_selector(parser, input, SelectorParsingState::INSIDE_NEGATION)? {
1974
Some(SimpleSelectorParseResult::SimpleSelector(s)) => {
1975
sequence.push(s);
1976
},
1977
None => {
1978
return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation));
1979
},
1980
Some(SimpleSelectorParseResult::PseudoElement(_)) |
1981
Some(SimpleSelectorParseResult::PartPseudo(_)) |
1982
Some(SimpleSelectorParseResult::SlottedPseudo(_)) => {
1983
let e = SelectorParseErrorKind::NonSimpleSelectorInNegation;
1984
return Err(input.new_custom_error(e));
1985
},
1986
}
1987
}
1988