@@ -74,18 +74,24 @@ impl core::fmt::Display for PseudoClasses {
74
74
}
75
75
}
76
76
77
+ /// The CSS pseudo-elements.
77
78
#[ cfg_attr( debug_assertions, compatibility_enum_check( selector) ) ]
78
- #[ derive( Clone , Debug , serde:: Serialize , serde:: Deserialize ) ]
79
- pub ( crate ) enum PseudoElements {
79
+ #[ derive( Clone , Debug , PartialEq , Eq , serde:: Serialize , serde:: Deserialize ) ]
80
+ pub enum PseudoElements {
81
+ /// The `::before` pseudo-element.
80
82
Before ,
83
+ /// The `::after` pseudo-element.
81
84
After ,
85
+ /// The `::selection` pseudo-element.
86
+ Selection ,
82
87
}
83
88
84
89
impl core:: fmt:: Display for PseudoElements {
85
90
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
86
91
let s = match self {
87
92
Self :: Before => "before" ,
88
93
Self :: After => "after" ,
94
+ Self :: Selection => "selection" ,
89
95
} ;
90
96
write ! ( f, "{}" , s)
91
97
}
@@ -389,24 +395,43 @@ impl Selector {
389
395
let mut cur_frag = frag;
390
396
loop {
391
397
let mut matches = true ;
398
+
399
+ // fails if id/tag_name not matching
392
400
if ( !cur_frag. id . is_empty ( )
393
401
&& ( !same_scope || Some ( cur_frag. id . as_str ( ) ) != cur_query. id ( ) ) )
394
402
|| ( !cur_frag. tag_name . is_empty ( )
395
403
&& ( !same_scope || cur_frag. tag_name != cur_query. tag_name ( ) ) )
396
404
{
397
405
matches = false
398
- } else if let Some ( pc) = cur_frag. pseudo_classes . as_ref ( ) {
399
- match & * * pc {
400
- PseudoClasses :: Host => {
401
- if sheet_style_scope. is_some ( )
402
- && sheet_style_scope != cur_query. host_style_scope ( )
403
- {
404
- matches = false
406
+ }
407
+
408
+ // fails if pseudo classes not matching
409
+ if matches {
410
+ if let Some ( pc) = cur_frag. pseudo_classes . as_ref ( ) {
411
+ // currently we only check `:host`
412
+ match & * * pc {
413
+ PseudoClasses :: Host => {
414
+ if sheet_style_scope. is_some ( )
415
+ && sheet_style_scope != cur_query. host_style_scope ( )
416
+ {
417
+ matches = false
418
+ }
405
419
}
420
+ _ => matches = false ,
406
421
}
407
- _ => matches = false ,
408
422
}
409
- } else {
423
+ }
424
+
425
+ // fails if pseudo classes not matching
426
+ if matches {
427
+ let pc = cur_frag. pseudo_elements . as_ref ( ) . map ( |x| ( * * x) . clone ( ) ) ;
428
+ if pc != cur_query. pseudo_element ( ) {
429
+ matches = false
430
+ }
431
+ }
432
+
433
+ // fails if any class not matching
434
+ if matches {
410
435
for class_name in cur_frag. classes . iter ( ) {
411
436
if !cur_query. classes ( ) . any ( |x| {
412
437
( sheet_style_scope. is_none ( ) || sheet_style_scope == x. scope ( ) )
@@ -415,84 +440,87 @@ impl Selector {
415
440
matches = false ;
416
441
}
417
442
}
443
+ }
418
444
419
- if matches {
420
- if let Some ( selector_attributes) = & cur_frag. attributes {
421
- for attribute in selector_attributes. iter ( ) {
422
- let selector_attr_value =
423
- attribute. value . as_deref ( ) . unwrap_or_default ( ) ;
424
- if let Some ( ( element_attr_value, sensitivity) ) =
425
- cur_query. attribute ( & attribute. name )
426
- {
427
- let sensitivity = match ( & attribute. case_insensitive , sensitivity) {
428
- ( AttributeFlags :: CaseInsensitive , _) | ( AttributeFlags :: CaseSensitivityDependsOnName , StyleNodeAttributeCaseSensitivity :: CaseInsensitive ) => {
429
- StyleNodeAttributeCaseSensitivity :: CaseInsensitive
430
- }
431
- ( AttributeFlags :: CaseSensitive , _) | ( AttributeFlags :: CaseSensitivityDependsOnName , StyleNodeAttributeCaseSensitivity :: CaseSensitive ) => {
432
- StyleNodeAttributeCaseSensitivity :: CaseSensitive
433
- }
434
- } ;
435
- if !match attribute. operator {
436
- AttributeOperator :: Set => true ,
437
- AttributeOperator :: Exact => sensitivity
438
- . eq ( element_attr_value, selector_attr_value) ,
439
- AttributeOperator :: List => {
440
- if selector_attr_value. is_empty ( ) {
441
- false
442
- } else {
443
- element_attr_value
444
- . split ( SELECTOR_WHITESPACE )
445
- . any ( |x| {
446
- sensitivity
447
- . eq ( x, selector_attr_value)
448
- } )
449
- }
450
- }
451
- AttributeOperator :: Hyphen => {
452
- #[ allow( clippy:: comparison_chain) ]
453
- if element_attr_value. len ( )
454
- < selector_attr_value. len ( )
455
- {
456
- false
457
- } else if element_attr_value. len ( )
458
- == selector_attr_value. len ( )
459
- {
460
- element_attr_value == selector_attr_value
461
- } else {
462
- sensitivity. starts_with (
463
- element_attr_value,
464
- & alloc:: format!(
465
- "{}-" ,
466
- selector_attr_value
467
- ) ,
468
- )
469
- }
445
+ // fails if any attribute not matching
446
+ if matches {
447
+ if let Some ( selector_attributes) = & cur_frag. attributes {
448
+ for attribute in selector_attributes. iter ( ) {
449
+ let selector_attr_value =
450
+ attribute. value . as_deref ( ) . unwrap_or_default ( ) ;
451
+ if let Some ( ( element_attr_value, sensitivity) ) =
452
+ cur_query. attribute ( & attribute. name )
453
+ {
454
+ let sensitivity = match ( & attribute. case_insensitive , sensitivity) {
455
+ ( AttributeFlags :: CaseInsensitive , _) | ( AttributeFlags :: CaseSensitivityDependsOnName , StyleNodeAttributeCaseSensitivity :: CaseInsensitive ) => {
456
+ StyleNodeAttributeCaseSensitivity :: CaseInsensitive
457
+ }
458
+ ( AttributeFlags :: CaseSensitive , _) | ( AttributeFlags :: CaseSensitivityDependsOnName , StyleNodeAttributeCaseSensitivity :: CaseSensitive ) => {
459
+ StyleNodeAttributeCaseSensitivity :: CaseSensitive
460
+ }
461
+ } ;
462
+ if !match attribute. operator {
463
+ AttributeOperator :: Set => true ,
464
+ AttributeOperator :: Exact => sensitivity
465
+ . eq ( element_attr_value, selector_attr_value) ,
466
+ AttributeOperator :: List => {
467
+ if selector_attr_value. is_empty ( ) {
468
+ false
469
+ } else {
470
+ element_attr_value
471
+ . split ( SELECTOR_WHITESPACE )
472
+ . any ( |x| {
473
+ sensitivity
474
+ . eq ( x, selector_attr_value)
475
+ } )
470
476
}
471
- AttributeOperator :: Begin => sensitivity
472
- . starts_with (
477
+ }
478
+ AttributeOperator :: Hyphen => {
479
+ #[ allow( clippy:: comparison_chain) ]
480
+ if element_attr_value. len ( )
481
+ < selector_attr_value. len ( )
482
+ {
483
+ false
484
+ } else if element_attr_value. len ( )
485
+ == selector_attr_value. len ( )
486
+ {
487
+ element_attr_value == selector_attr_value
488
+ } else {
489
+ sensitivity. starts_with (
473
490
element_attr_value,
474
- selector_attr_value,
475
- ) ,
476
- AttributeOperator :: End => sensitivity. ends_with (
477
- element_attr_value,
478
- selector_attr_value,
479
- ) ,
480
- AttributeOperator :: Contain => sensitivity. contains (
491
+ & alloc:: format!(
492
+ "{}-" ,
493
+ selector_attr_value
494
+ ) ,
495
+ )
496
+ }
497
+ }
498
+ AttributeOperator :: Begin => sensitivity
499
+ . starts_with (
481
500
element_attr_value,
482
501
selector_attr_value,
483
502
) ,
484
- } {
485
- matches = false ;
486
- break ;
487
- }
488
- } else {
503
+ AttributeOperator :: End => sensitivity. ends_with (
504
+ element_attr_value,
505
+ selector_attr_value,
506
+ ) ,
507
+ AttributeOperator :: Contain => sensitivity. contains (
508
+ element_attr_value,
509
+ selector_attr_value,
510
+ ) ,
511
+ } {
489
512
matches = false ;
490
513
break ;
491
514
}
515
+ } else {
516
+ matches = false ;
517
+ break ;
492
518
}
493
519
}
494
520
}
495
521
}
522
+
523
+ // check ancestors if not matches
496
524
if !matches {
497
525
if allow_ancestor {
498
526
cur_query = match query. next_back ( ) {
@@ -504,6 +532,8 @@ impl Selector {
504
532
}
505
533
continue ;
506
534
}
535
+
536
+ // check ancestors if the rule requires
507
537
if let Some ( ref relation) = cur_frag. relation {
508
538
cur_query = match query. next_back ( ) {
509
539
Some ( x) => x,
0 commit comments