@@ -74,18 +74,24 @@ impl core::fmt::Display for PseudoClasses {
7474 }
7575}
7676
77+ /// The CSS pseudo-elements.
7778#[ 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.
8082 Before ,
83+ /// The `::after` pseudo-element.
8184 After ,
85+ /// The `::selection` pseudo-element.
86+ Selection ,
8287}
8388
8489impl core:: fmt:: Display for PseudoElements {
8590 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
8691 let s = match self {
8792 Self :: Before => "before" ,
8893 Self :: After => "after" ,
94+ Self :: Selection => "selection" ,
8995 } ;
9096 write ! ( f, "{}" , s)
9197 }
@@ -389,24 +395,43 @@ impl Selector {
389395 let mut cur_frag = frag;
390396 loop {
391397 let mut matches = true ;
398+
399+ // fails if id/tag_name not matching
392400 if ( !cur_frag. id . is_empty ( )
393401 && ( !same_scope || Some ( cur_frag. id . as_str ( ) ) != cur_query. id ( ) ) )
394402 || ( !cur_frag. tag_name . is_empty ( )
395403 && ( !same_scope || cur_frag. tag_name != cur_query. tag_name ( ) ) )
396404 {
397405 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+ }
405419 }
420+ _ => matches = false ,
406421 }
407- _ => matches = false ,
408422 }
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 {
410435 for class_name in cur_frag. classes . iter ( ) {
411436 if !cur_query. classes ( ) . any ( |x| {
412437 ( sheet_style_scope. is_none ( ) || sheet_style_scope == x. scope ( ) )
@@ -415,84 +440,87 @@ impl Selector {
415440 matches = false ;
416441 }
417442 }
443+ }
418444
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+ } )
470476 }
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 (
473490 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 (
481500 element_attr_value,
482501 selector_attr_value,
483502 ) ,
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+ } {
489512 matches = false ;
490513 break ;
491514 }
515+ } else {
516+ matches = false ;
517+ break ;
492518 }
493519 }
494520 }
495521 }
522+
523+ // check ancestors if not matches
496524 if !matches {
497525 if allow_ancestor {
498526 cur_query = match query. next_back ( ) {
@@ -504,6 +532,8 @@ impl Selector {
504532 }
505533 continue ;
506534 }
535+
536+ // check ancestors if the rule requires
507537 if let Some ( ref relation) = cur_frag. relation {
508538 cur_query = match query. next_back ( ) {
509539 Some ( x) => x,
0 commit comments