1use alloc::{
2 boxed::Box,
3 string::{String, ToString},
4 vec::Vec,
5};
6use core::{cell::Cell, fmt, num::NonZeroUsize};
7
8use cssparser::{Parser, ParserInput};
9#[cfg(debug_assertions)]
10use float_pigment_css_macro::{compatibility_enum_check, compatibility_struct_check};
11
12use crate::parser::{parse_selector, ParseState};
13use crate::query::{StyleNode, StyleNodeAttributeCaseSensitivity, StyleNodeClass};
14
15#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
16#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
17pub(crate) enum SelectorRelationType {
18 None,
19 Ancestor(SelectorFragment),
20 DirectParent(SelectorFragment),
21 NextSibling(SelectorFragment),
22 SubsequentSibling(SelectorFragment),
23}
24
25#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
26#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
27#[allow(clippy::box_collection)] pub(crate) enum PseudoClasses {
29 Host,
30 FirstChild,
31 LastChild,
32 Empty,
33 Not(Vec<SelectorFragment>),
34 OnlyChild,
35 NthChild(i32, i32, Option<Box<Vec<SelectorFragment>>>),
36 NthOfType(i32, i32),
37}
38
39impl core::fmt::Display for PseudoClasses {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 let s = match self {
42 Self::Host => "host".to_string(),
43 Self::FirstChild => "first-child".to_string(),
44 Self::LastChild => "last-child".to_string(),
45 Self::Empty => "empty".to_string(),
46 Self::Not(selectors) => {
47 let selectors_str = selectors
48 .iter()
49 .map(|x| x.to_string())
50 .collect::<Vec<String>>()
51 .join(", ");
52 format!("not({})", selectors_str)
53 }
54 Self::OnlyChild => "only-child".to_string(),
55 Self::NthChild(a, b, selector_list) => {
56 if let Some(selectors) = selector_list {
57 format!(
58 "nth-child({}n + {} of {})",
59 a,
60 b,
61 selectors
62 .iter()
63 .map(|selector| selector.to_string())
64 .collect::<Vec<String>>()
65 .join(",")
66 )
67 } else {
68 format!("nth-child({}n + {})", a, b)
69 }
70 }
71 Self::NthOfType(a, b) => format!("nth-of-type({}n + {})", a, b),
72 };
73 write!(f, "{}", s)
74 }
75}
76
77#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
79#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
80pub enum PseudoElements {
81 Before,
83 After,
85 Selection,
87}
88
89impl core::fmt::Display for PseudoElements {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 let s = match self {
92 Self::Before => "before",
93 Self::After => "after",
94 Self::Selection => "selection",
95 };
96 write!(f, "{}", s)
97 }
98}
99
100pub(crate) static SELECTOR_WHITESPACE: &[char] = &[' ', '\t', '\n', '\r', '\x0C'];
101
102#[repr(C)]
103#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
104#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
105#[allow(clippy::enum_variant_names)]
106pub(crate) enum AttributeFlags {
107 CaseSensitivityDependsOnName, CaseSensitive, CaseInsensitive, }
111
112#[repr(C)]
113#[cfg_attr(debug_assertions, compatibility_enum_check(selector))]
114#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
115pub(crate) enum AttributeOperator {
116 Set,
117 Exact,
118 List,
119 Hyphen,
120 Begin,
121 End,
122 Contain,
123}
124
125#[cfg_attr(debug_assertions, compatibility_struct_check(selector))]
126#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
127pub(crate) struct Attribute {
128 pub(crate) operator: AttributeOperator,
129 pub(crate) case_insensitive: AttributeFlags,
130 pub(crate) never_matches: bool,
131 pub(crate) name: String,
132 pub(crate) value: Option<String>,
133}
134
135impl Attribute {
136 pub(crate) fn new_set(name: String) -> Self {
137 Self {
138 operator: AttributeOperator::Set,
139 case_insensitive: AttributeFlags::CaseSensitivityDependsOnName,
140 never_matches: false,
141 name,
142 value: None,
143 }
144 }
145}
146
147impl core::fmt::Display for Attribute {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 let mut s = self.name.to_string();
150 match self.operator {
151 AttributeOperator::Set => {
152 return write!(f, "{}", s);
153 }
154 AttributeOperator::Exact => s.push('='),
155 AttributeOperator::List => s.push_str("~="),
156 AttributeOperator::Begin => s.push_str("^="),
157 AttributeOperator::End => s.push_str("$="),
158 AttributeOperator::Contain => s.push_str("*="),
159 AttributeOperator::Hyphen => s.push_str("|="),
160 };
161 s.push_str(&format!("\"{}\"", self.value.as_ref().unwrap()));
162 match self.case_insensitive {
163 AttributeFlags::CaseInsensitive => s.push_str(" i"),
164 AttributeFlags::CaseSensitive => s.push_str(" s"),
165 AttributeFlags::CaseSensitivityDependsOnName => {}
166 }
167 write!(f, "{}", s)
168 }
169}
170
171#[cfg_attr(debug_assertions, compatibility_struct_check(selector))]
173#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
174#[allow(clippy::box_collection)] pub(crate) struct SelectorFragment {
176 pub(crate) tag_name: String,
177 pub(crate) id: String,
178 pub(crate) classes: Vec<String>,
179 pub(crate) relation: Option<Box<SelectorRelationType>>,
180 weight: Cell<u16>,
181 pub(crate) pseudo_classes: Option<Box<PseudoClasses>>,
182 pub(crate) pseudo_elements: Option<Box<PseudoElements>>,
183 pub(crate) attributes: Option<Box<Vec<Attribute>>>,
184}
185
186impl fmt::Display for SelectorFragment {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 if let Some(relation) = &self.relation {
189 match &**relation {
190 SelectorRelationType::None => {}
191 SelectorRelationType::Ancestor(x) => write!(f, "{} ", x)?,
192 SelectorRelationType::DirectParent(x) => write!(f, "{} > ", x)?,
193 SelectorRelationType::NextSibling(x) => write!(f, "{} + ", x)?,
194 SelectorRelationType::SubsequentSibling(x) => write!(f, "{} ~ ", x)?,
195 }
196 }
197 if !self.tag_name.is_empty() {
198 write!(f, "{}", self.tag_name)?;
199 }
200 if !self.id.is_empty() {
201 write!(f, "#{}", self.id)?;
202 }
203 for class in self.classes.iter() {
204 write!(f, ".{}", class)?;
205 }
206 if self.pseudo_classes.is_some() {
207 write!(f, ":{}", self.pseudo_classes.as_ref().unwrap())?;
208 }
209 if self.pseudo_elements.is_some() {
210 write!(f, "::{}", self.pseudo_elements.as_ref().unwrap())?;
211 }
212 if let Some(attributes) = self.attributes.as_ref() {
213 for attr in attributes.iter() {
214 write!(f, "[{}]", attr)?;
215 }
216 }
217 Ok(())
218 }
219}
220
221impl SelectorFragment {
222 pub(crate) fn new() -> Self {
223 Self {
224 tag_name: String::new(),
225 id: String::new(),
226 classes: vec![],
227 relation: None,
228 weight: Cell::new(0),
229 pseudo_classes: None,
230 pseudo_elements: None,
231 attributes: None,
232 }
233 }
234 pub(crate) fn with_relation(parent: SelectorRelationType) -> Self {
235 Self {
236 tag_name: String::new(),
237 id: String::new(),
238 classes: vec![],
239 relation: Some(Box::new(parent)),
240 weight: Cell::new(0),
241 pseudo_classes: None,
242 pseudo_elements: None,
243 attributes: None,
244 }
245 }
246 pub(crate) fn weight(&self) -> u16 {
247 let mut weight = self.weight.get();
248 if weight > 0 {
249 return weight;
250 }
251 if !self.tag_name.is_empty() {
252 weight += 1 << 0;
253 }
254 if !self.id.is_empty() {
255 weight += 1 << 13;
256 }
257 let class_and_attr_count = self.classes.len()
258 + self
259 .attributes
260 .as_ref()
261 .map(|a| a.len())
262 .unwrap_or_default();
263 weight += (class_and_attr_count.min(0xff) << 5) as u16;
264 if let Some(ref relation) = self.relation {
265 weight += match &**relation {
266 SelectorRelationType::None => 0,
267 SelectorRelationType::Ancestor(x) => x.weight(),
268 SelectorRelationType::DirectParent(x) => x.weight(),
269 SelectorRelationType::NextSibling(x) => x.weight(),
270 SelectorRelationType::SubsequentSibling(x) => x.weight(),
271 }
272 }
273 if self.pseudo_classes.as_ref().is_some() {
274 weight += 1 << 5;
275 }
276 self.weight.set(weight);
277 weight
278 }
279 pub(crate) fn set_tag_name(&mut self, tag_name: &str) {
280 self.tag_name = tag_name.into();
281 }
282 pub(crate) fn set_id(&mut self, id: &str) {
283 self.id = id.into();
284 }
285 pub(crate) fn add_class(&mut self, class: &str) {
286 self.classes.push(class.into())
287 }
288 #[cfg(feature = "deserialize")]
289 pub(crate) fn set_basics(&mut self, tag_name: String, id: String, classes: Vec<String>) {
290 self.tag_name = tag_name;
291 self.id = id;
292 self.classes = classes;
293 }
294 pub(crate) fn set_pseudo_classes(&mut self, pseudo_classes: PseudoClasses) {
295 self.pseudo_classes = Some(Box::new(pseudo_classes));
296 }
297 pub(crate) fn set_pseudo_elements(&mut self, pseudo_elements: PseudoElements) {
298 self.pseudo_elements = Some(Box::new(pseudo_elements));
299 }
300 pub(crate) fn add_attribute(&mut self, attribute: Attribute) {
301 if self.attributes.is_none() {
302 self.attributes.replace(Box::new(Vec::with_capacity(1)));
303 }
304 if let Some(ref mut attributes) = self.attributes {
305 attributes.push(attribute);
306 }
307 }
308 pub(crate) fn add_tag_name_prefix(&mut self, prefix: &str) {
309 if !self.tag_name.is_empty() {
310 self.tag_name = format!("{}{}", prefix, self.tag_name);
311 }
312 if let Some(parent) = self.relation.as_mut() {
313 match parent.as_mut() {
314 SelectorRelationType::Ancestor(frag) => {
315 frag.add_tag_name_prefix(prefix);
316 }
317 SelectorRelationType::DirectParent(frag) => {
318 frag.add_tag_name_prefix(prefix);
319 }
320 _ => {}
321 }
322 }
323 }
324}
325
326#[cfg_attr(debug_assertions, compatibility_struct_check(selector))]
327#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
328pub(crate) struct Selector {
329 pub(crate) fragments: Vec<SelectorFragment>,
330 pub(crate) max_weight: u16,
331}
332
333impl fmt::Display for Selector {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 write!(
336 f,
337 "{}",
338 self.fragments
339 .iter()
340 .map(|f| f.to_string())
341 .collect::<Box<[String]>>()
342 .join(", ")
343 )
344 }
345}
346
347impl Selector {
348 pub(crate) fn star_selector() -> Self {
349 Self {
350 fragments: vec![SelectorFragment::new()],
351 max_weight: 0,
352 }
353 }
354 pub(crate) fn from_fragments(fragments: Vec<SelectorFragment>) -> Self {
355 let mut max_weight = 0;
356 for f in fragments.iter() {
357 let w = f.weight();
358 if w > max_weight {
359 max_weight = w;
360 }
361 }
362 Self {
363 fragments,
364 max_weight,
365 }
366 }
367 pub(crate) fn get_index_classes(&self) -> Vec<String> {
368 let mut ret = vec![];
369 for frag in self.fragments.iter() {
370 let s = if !frag.classes.is_empty() {
371 frag.classes[0].clone()
372 } else {
373 String::new()
374 };
375 if !ret.contains(&s) {
376 ret.push(s)
377 }
378 }
379 ret
380 }
381 pub(crate) fn match_query<T: StyleNode>(
382 &self,
383 query: &[T],
384 sheet_style_scope: Option<NonZeroUsize>,
385 ) -> Option<u16> {
386 let mut cur_weight = 0;
387 'f: for frag in self.fragments.iter() {
388 let mut query = query.iter();
389 match query.next_back() {
390 Some(mut cur_query) => {
391 let same_scope = sheet_style_scope.is_none()
392 || sheet_style_scope == cur_query.style_scope()
393 || sheet_style_scope == cur_query.extra_style_scope();
394 let mut allow_ancestor = false;
395 let mut cur_frag = frag;
396 loop {
397 let mut matches = true;
398
399 if (!cur_frag.id.is_empty()
401 && (!same_scope || Some(cur_frag.id.as_str()) != cur_query.id()))
402 || (!cur_frag.tag_name.is_empty()
403 && (!same_scope || cur_frag.tag_name != cur_query.tag_name()))
404 {
405 matches = false
406 }
407
408 if matches {
410 if let Some(pc) = cur_frag.pseudo_classes.as_ref() {
411 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 }
419 }
420 _ => matches = false,
421 }
422 }
423 }
424
425 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 if matches {
435 for class_name in cur_frag.classes.iter() {
436 if !cur_query.classes().any(|x| {
437 (sheet_style_scope.is_none() || sheet_style_scope == x.scope())
438 && x.name() == class_name
439 }) {
440 matches = false;
441 }
442 }
443 }
444
445 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 (
455 &attribute.case_insensitive,
456 sensitivity,
457 ) {
458 (AttributeFlags::CaseInsensitive, _)
459 | (
460 AttributeFlags::CaseSensitivityDependsOnName,
461 StyleNodeAttributeCaseSensitivity::CaseInsensitive,
462 ) => StyleNodeAttributeCaseSensitivity::CaseInsensitive,
463 (AttributeFlags::CaseSensitive, _)
464 | (
465 AttributeFlags::CaseSensitivityDependsOnName,
466 StyleNodeAttributeCaseSensitivity::CaseSensitive,
467 ) => StyleNodeAttributeCaseSensitivity::CaseSensitive,
468 };
469 if !match attribute.operator {
470 AttributeOperator::Set => true,
471 AttributeOperator::Exact => sensitivity
472 .eq(element_attr_value, selector_attr_value),
473 AttributeOperator::List => {
474 if selector_attr_value.is_empty() {
475 false
476 } else {
477 element_attr_value
478 .split(SELECTOR_WHITESPACE)
479 .any(|x| {
480 sensitivity.eq(x, selector_attr_value)
481 })
482 }
483 }
484 AttributeOperator::Hyphen => {
485 #[allow(clippy::comparison_chain)]
486 if element_attr_value.len()
487 < selector_attr_value.len()
488 {
489 false
490 } else if element_attr_value.len()
491 == selector_attr_value.len()
492 {
493 element_attr_value == selector_attr_value
494 } else {
495 sensitivity.starts_with(
496 element_attr_value,
497 &alloc::format!("{}-", selector_attr_value),
498 )
499 }
500 }
501 AttributeOperator::Begin => sensitivity.starts_with(
502 element_attr_value,
503 selector_attr_value,
504 ),
505 AttributeOperator::End => sensitivity
506 .ends_with(element_attr_value, selector_attr_value),
507 AttributeOperator::Contain => sensitivity
508 .contains(element_attr_value, selector_attr_value),
509 } {
510 matches = false;
511 break;
512 }
513 } else {
514 matches = false;
515 break;
516 }
517 }
518 }
519 }
520
521 if !matches {
523 if allow_ancestor {
524 cur_query = match query.next_back() {
525 Some(x) => x,
526 None => continue 'f,
527 }
528 } else {
529 continue 'f;
530 }
531 continue;
532 }
533
534 if let Some(ref relation) = cur_frag.relation {
536 cur_query = match query.next_back() {
537 Some(x) => x,
538 None => continue 'f,
539 };
540 match &**relation {
541 SelectorRelationType::None => {
542 }
544 SelectorRelationType::Ancestor(x) => {
545 cur_frag = x;
546 allow_ancestor = true;
547 }
548 SelectorRelationType::DirectParent(x) => {
549 cur_frag = x;
550 allow_ancestor = false;
551 }
552 SelectorRelationType::NextSibling(x) => {
553 cur_frag = x;
554 allow_ancestor = false;
555 }
556 SelectorRelationType::SubsequentSibling(x) => {
557 cur_frag = x;
558 allow_ancestor = false
559 }
560 }
561 } else {
562 break;
563 }
564 }
565 }
566 None => break,
567 }
568 let w = frag.weight();
569 if w == self.max_weight {
570 return Some(w);
571 }
572 cur_weight = w;
573 }
574 if cur_weight > 0 {
575 Some(cur_weight)
576 } else {
577 None
578 }
579 }
580 pub(crate) fn from_string(selector_str: &str) -> Selector {
581 let mut parser_input = ParserInput::new(selector_str);
582 let mut parser = Parser::new(&mut parser_input);
583 let mut st = ParseState::new(None, crate::parser::StyleParsingDebugMode::None, None);
584 let selector = parse_selector(&mut parser, &mut st);
585 if let Ok(ret) = selector {
586 return ret;
587 }
588 Selector::default()
589 }
590}