@@ -99,8 +99,67 @@ static zend_always_inline dom_lxb_str_wrapper lxb_selectors_adapted_attr_value(c
9999 return ret ;
100100}
101101
102+ static bool lxb_selectors_attrib_name_cmp (const lxb_css_selector_t * selector , const char * name , size_t len )
103+ {
104+ return selector -> name .length == len && lexbor_str_data_nlocmp_right ((const lxb_char_t * ) name , selector -> name .data , len );
105+ }
106+
107+ /* From https://html.spec.whatwg.org/#case-sensitivity-of-selectors
108+ * "Attribute selectors on an HTML element in an HTML document must treat the values of attributes with the following names as ASCII case-insensitive:" */
109+ static bool lxb_selectors_is_lowercased_html_attrib_name (const lxb_css_selector_t * selector )
110+ {
111+ return lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("accept" ))
112+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("accept-charset" ))
113+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("align" ))
114+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("alink" ))
115+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("axis" ))
116+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("bgcolor" ))
117+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("charset" ))
118+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("checked" ))
119+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("clear" ))
120+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("codetype" ))
121+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("color" ))
122+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("compact" ))
123+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("declare" ))
124+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("defer" ))
125+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("dir" ))
126+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("direction" ))
127+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("disabled" ))
128+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("enctype" ))
129+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("face" ))
130+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("frame" ))
131+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("hreflang" ))
132+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("http-equiv" ))
133+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("lang" ))
134+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("language" ))
135+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("link" ))
136+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("media" ))
137+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("method" ))
138+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("multiple" ))
139+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("nohref" ))
140+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("noresize" ))
141+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("noshade" ))
142+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("nowrap" ))
143+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("readonly" ))
144+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("rel" ))
145+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("rev" ))
146+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("rules" ))
147+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("scope" ))
148+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("scrolling" ))
149+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("selected" ))
150+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("shape" ))
151+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("target" ))
152+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("text" ))
153+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("type" ))
154+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("valign" ))
155+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("valuetype" ))
156+ || lxb_selectors_attrib_name_cmp (selector , ZEND_STRL ("vlink" ));
157+ }
158+
102159static void lxb_selectors_adapted_set_entry_id_ex (lxb_selectors_entry_t * entry , const lxb_css_selector_t * selector , const xmlNode * node )
103160{
161+ entry -> id .attr_case_insensitive = lxb_selectors_is_lowercased_html_attrib_name (selector );
162+
104163 if (node -> doc != NULL && node -> doc -> dict != NULL ) {
105164 const xmlChar * interned = xmlDictExists (node -> doc -> dict , selector -> name .data , selector -> name .length );
106165 if (interned != NULL ) {
@@ -1304,10 +1363,10 @@ lxb_selectors_match_class(const lexbor_str_t *target, const lexbor_str_t *src,
13041363}
13051364
13061365static bool
1307- lxb_selectors_match_attribute_value (const lxb_css_selector_attribute_t * attr , const lexbor_str_t * trg , const lexbor_str_t * src )
1366+ lxb_selectors_match_attribute_value (const lxb_css_selector_attribute_t * attr , bool force_modifier_i , const lexbor_str_t * trg , const lexbor_str_t * src )
13081367{
13091368 bool res ;
1310- bool ins = attr -> modifier == LXB_CSS_SELECTOR_MODIFIER_I ;
1369+ bool ins = attr -> modifier == LXB_CSS_SELECTOR_MODIFIER_I || force_modifier_i ;
13111370
13121371 switch (attr -> match ) {
13131372 case LXB_CSS_SELECTOR_MATCH_EQUAL : /* = */
@@ -1419,7 +1478,13 @@ lxb_selectors_match_attribute(const lxb_css_selector_t *selector,
14191478 }
14201479
14211480 dom_lxb_str_wrapper trg = lxb_selectors_adapted_attr_value (dom_attr );
1422- bool res = lxb_selectors_match_attribute_value (attr , & trg .str , src );
1481+ ZEND_ASSERT (node -> doc != NULL );
1482+ bool res = lxb_selectors_match_attribute_value (
1483+ attr ,
1484+ entry -> id .attr_case_insensitive && php_dom_ns_is_html_and_document_is_html (node ),
1485+ & trg .str ,
1486+ src
1487+ );
14231488 dom_lxb_str_wrapper_release (& trg );
14241489 return res ;
14251490}
0 commit comments