Selector.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
  3. * Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "Selector.h"
  8. #include <AK/GenericShorthands.h>
  9. #include <LibWeb/CSS/Serialize.h>
  10. namespace Web::CSS {
  11. Selector::Selector(Vector<CompoundSelector>&& compound_selectors)
  12. : m_compound_selectors(move(compound_selectors))
  13. {
  14. // FIXME: This assumes that only one pseudo-element is allowed in a selector, and that it appears at the end.
  15. // This is not true in Selectors-4!
  16. if (!m_compound_selectors.is_empty()) {
  17. for (auto const& simple_selector : m_compound_selectors.last().simple_selectors) {
  18. if (simple_selector.type == SimpleSelector::Type::PseudoElement) {
  19. m_pseudo_element = simple_selector.pseudo_element();
  20. break;
  21. }
  22. }
  23. }
  24. // https://drafts.csswg.org/css-nesting-1/#contain-the-nesting-selector
  25. // "A selector is said to contain the nesting selector if, when it was parsed as any type of selector,
  26. // a <delim-token> with the value "&" (U+0026 AMPERSAND) was encountered."
  27. for (auto const& compound_selector : m_compound_selectors) {
  28. for (auto const& simple_selector : compound_selector.simple_selectors) {
  29. if (simple_selector.type == SimpleSelector::Type::Nesting) {
  30. m_contains_the_nesting_selector = true;
  31. break;
  32. }
  33. if (simple_selector.type == SimpleSelector::Type::PseudoClass) {
  34. for (auto const& child_selector : simple_selector.pseudo_class().argument_selector_list) {
  35. if (child_selector->contains_the_nesting_selector()) {
  36. m_contains_the_nesting_selector = true;
  37. break;
  38. }
  39. }
  40. if (m_contains_the_nesting_selector)
  41. break;
  42. }
  43. }
  44. if (m_contains_the_nesting_selector)
  45. break;
  46. }
  47. collect_ancestor_hashes();
  48. }
  49. void Selector::collect_ancestor_hashes()
  50. {
  51. size_t next_hash_index = 0;
  52. auto append_unique_hash = [&](u32 hash) -> bool {
  53. if (next_hash_index >= m_ancestor_hashes.size())
  54. return true;
  55. for (size_t i = 0; i < next_hash_index; ++i) {
  56. if (m_ancestor_hashes[i] == hash)
  57. return false;
  58. }
  59. m_ancestor_hashes[next_hash_index++] = hash;
  60. return false;
  61. };
  62. auto last_combinator = m_compound_selectors.last().combinator;
  63. for (ssize_t compound_selector_index = static_cast<ssize_t>(m_compound_selectors.size()) - 2; compound_selector_index >= 0; --compound_selector_index) {
  64. auto const& compound_selector = m_compound_selectors[compound_selector_index];
  65. if (last_combinator == Combinator::Descendant || last_combinator == Combinator::ImmediateChild) {
  66. for (auto const& simple_selector : compound_selector.simple_selectors) {
  67. switch (simple_selector.type) {
  68. case SimpleSelector::Type::Id:
  69. case SimpleSelector::Type::Class:
  70. if (append_unique_hash(simple_selector.name().hash()))
  71. return;
  72. break;
  73. case SimpleSelector::Type::TagName:
  74. if (append_unique_hash(simple_selector.qualified_name().name.name.hash()))
  75. return;
  76. break;
  77. case SimpleSelector::Type::Attribute:
  78. if (append_unique_hash(simple_selector.attribute().qualified_name.name.name.hash()))
  79. return;
  80. break;
  81. default:
  82. break;
  83. }
  84. }
  85. }
  86. last_combinator = compound_selector.combinator;
  87. }
  88. for (size_t i = next_hash_index; i < m_ancestor_hashes.size(); ++i)
  89. m_ancestor_hashes[i] = 0;
  90. }
  91. // https://www.w3.org/TR/selectors-4/#specificity-rules
  92. u32 Selector::specificity() const
  93. {
  94. if (m_specificity.has_value())
  95. return *m_specificity;
  96. constexpr u32 ids_shift = 16;
  97. constexpr u32 classes_shift = 8;
  98. constexpr u32 tag_names_shift = 0;
  99. constexpr u32 ids_mask = 0xff << ids_shift;
  100. constexpr u32 classes_mask = 0xff << classes_shift;
  101. constexpr u32 tag_names_mask = 0xff << tag_names_shift;
  102. u32 ids = 0;
  103. u32 classes = 0;
  104. u32 tag_names = 0;
  105. auto count_specificity_of_most_complex_selector = [&](auto& selector_list) {
  106. u32 max_selector_list_argument_specificity = 0;
  107. for (auto const& complex_selector : selector_list) {
  108. max_selector_list_argument_specificity = max(max_selector_list_argument_specificity, complex_selector->specificity());
  109. }
  110. u32 child_ids = (max_selector_list_argument_specificity & ids_mask) >> ids_shift;
  111. u32 child_classes = (max_selector_list_argument_specificity & classes_mask) >> classes_shift;
  112. u32 child_tag_names = (max_selector_list_argument_specificity & tag_names_mask) >> tag_names_shift;
  113. ids += child_ids;
  114. classes += child_classes;
  115. tag_names += child_tag_names;
  116. };
  117. for (auto& list : m_compound_selectors) {
  118. for (auto& simple_selector : list.simple_selectors) {
  119. switch (simple_selector.type) {
  120. case SimpleSelector::Type::Id:
  121. // count the number of ID selectors in the selector (= A)
  122. ++ids;
  123. break;
  124. case SimpleSelector::Type::Class:
  125. case SimpleSelector::Type::Attribute:
  126. // count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= B)
  127. ++classes;
  128. break;
  129. case SimpleSelector::Type::PseudoClass: {
  130. auto& pseudo_class = simple_selector.pseudo_class();
  131. switch (pseudo_class.type) {
  132. case PseudoClass::Has:
  133. case PseudoClass::Is:
  134. case PseudoClass::Not: {
  135. // The specificity of an :is(), :not(), or :has() pseudo-class is replaced by the
  136. // specificity of the most specific complex selector in its selector list argument.
  137. count_specificity_of_most_complex_selector(pseudo_class.argument_selector_list);
  138. break;
  139. }
  140. case PseudoClass::NthChild:
  141. case PseudoClass::NthLastChild: {
  142. // Analogously, the specificity of an :nth-child() or :nth-last-child() selector
  143. // is the specificity of the pseudo class itself (counting as one pseudo-class selector)
  144. // plus the specificity of the most specific complex selector in its selector list argument (if any).
  145. ++classes;
  146. count_specificity_of_most_complex_selector(pseudo_class.argument_selector_list);
  147. break;
  148. }
  149. case PseudoClass::Where:
  150. // The specificity of a :where() pseudo-class is replaced by zero.
  151. break;
  152. default:
  153. ++classes;
  154. break;
  155. }
  156. break;
  157. }
  158. case SimpleSelector::Type::TagName:
  159. case SimpleSelector::Type::PseudoElement:
  160. // count the number of type selectors and pseudo-elements in the selector (= C)
  161. ++tag_names;
  162. break;
  163. case SimpleSelector::Type::Universal:
  164. // ignore the universal selector
  165. break;
  166. case SimpleSelector::Type::Nesting:
  167. // We should have replaced this already
  168. VERIFY_NOT_REACHED();
  169. }
  170. }
  171. }
  172. // Due to storage limitations, implementations may have limitations on the size of A, B, or C.
  173. // If so, values higher than the limit must be clamped to that limit, and not overflow.
  174. m_specificity = (min(ids, 0xff) << ids_shift)
  175. + (min(classes, 0xff) << classes_shift)
  176. + (min(tag_names, 0xff) << tag_names_shift);
  177. return *m_specificity;
  178. }
  179. // https://www.w3.org/TR/cssom/#serialize-a-simple-selector
  180. String Selector::SimpleSelector::serialize() const
  181. {
  182. StringBuilder s;
  183. switch (type) {
  184. case Selector::SimpleSelector::Type::TagName:
  185. case Selector::SimpleSelector::Type::Universal: {
  186. auto qualified_name = this->qualified_name();
  187. // 1. If the namespace prefix maps to a namespace that is not the default namespace and is not the null
  188. // namespace (not in a namespace) append the serialization of the namespace prefix as an identifier,
  189. // followed by a "|" (U+007C) to s.
  190. if (qualified_name.namespace_type == QualifiedName::NamespaceType::Named) {
  191. serialize_an_identifier(s, qualified_name.namespace_);
  192. s.append('|');
  193. }
  194. // 2. If the namespace prefix maps to a namespace that is the null namespace (not in a namespace)
  195. // append "|" (U+007C) to s.
  196. if (qualified_name.namespace_type == QualifiedName::NamespaceType::None)
  197. s.append('|');
  198. // 3. If this is a type selector append the serialization of the element name as an identifier to s.
  199. if (type == Selector::SimpleSelector::Type::TagName)
  200. serialize_an_identifier(s, qualified_name.name.name);
  201. // 4. If this is a universal selector append "*" (U+002A) to s.
  202. if (type == Selector::SimpleSelector::Type::Universal)
  203. s.append('*');
  204. break;
  205. }
  206. case Selector::SimpleSelector::Type::Attribute: {
  207. auto& attribute = this->attribute();
  208. // 1. Append "[" (U+005B) to s.
  209. s.append('[');
  210. // 2. If the namespace prefix maps to a namespace that is not the null namespace (not in a namespace)
  211. // append the serialization of the namespace prefix as an identifier, followed by a "|" (U+007C) to s.
  212. if (attribute.qualified_name.namespace_type == QualifiedName::NamespaceType::Named) {
  213. serialize_an_identifier(s, attribute.qualified_name.namespace_);
  214. s.append('|');
  215. }
  216. // 3. Append the serialization of the attribute name as an identifier to s.
  217. serialize_an_identifier(s, attribute.qualified_name.name.name);
  218. // 4. If there is an attribute value specified, append "=", "~=", "|=", "^=", "$=", or "*=" as appropriate (depending on the type of attribute selector),
  219. // followed by the serialization of the attribute value as a string, to s.
  220. if (!attribute.value.is_empty()) {
  221. switch (attribute.match_type) {
  222. case Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch:
  223. s.append("="sv);
  224. break;
  225. case Selector::SimpleSelector::Attribute::MatchType::ContainsWord:
  226. s.append("~="sv);
  227. break;
  228. case Selector::SimpleSelector::Attribute::MatchType::ContainsString:
  229. s.append("*="sv);
  230. break;
  231. case Selector::SimpleSelector::Attribute::MatchType::StartsWithSegment:
  232. s.append("|="sv);
  233. break;
  234. case Selector::SimpleSelector::Attribute::MatchType::StartsWithString:
  235. s.append("^="sv);
  236. break;
  237. case Selector::SimpleSelector::Attribute::MatchType::EndsWithString:
  238. s.append("$="sv);
  239. break;
  240. default:
  241. break;
  242. }
  243. serialize_a_string(s, attribute.value);
  244. }
  245. // 5. If the attribute selector has the case-insensitivity flag present, append " i" (U+0020 U+0069) to s.
  246. // If the attribute selector has the case-insensitivity flag present, append " s" (U+0020 U+0073) to s.
  247. // (the line just above is an addition to CSS OM to match Selectors Level 4 last draft)
  248. switch (attribute.case_type) {
  249. case Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch:
  250. s.append(" i"sv);
  251. break;
  252. case Selector::SimpleSelector::Attribute::CaseType::CaseSensitiveMatch:
  253. s.append(" s"sv);
  254. break;
  255. default:
  256. break;
  257. }
  258. // 6. Append "]" (U+005D) to s.
  259. s.append(']');
  260. break;
  261. }
  262. case Selector::SimpleSelector::Type::Class:
  263. // Append a "." (U+002E), followed by the serialization of the class name as an identifier to s.
  264. s.append('.');
  265. serialize_an_identifier(s, name());
  266. break;
  267. case Selector::SimpleSelector::Type::Id:
  268. // Append a "#" (U+0023), followed by the serialization of the ID as an identifier to s.
  269. s.append('#');
  270. serialize_an_identifier(s, name());
  271. break;
  272. case Selector::SimpleSelector::Type::PseudoClass: {
  273. auto& pseudo_class = this->pseudo_class();
  274. auto metadata = pseudo_class_metadata(pseudo_class.type);
  275. // HACK: `:host()` has both a function and a non-function form, so handle that first.
  276. // It's also not in the spec.
  277. if (pseudo_class.type == PseudoClass::Host) {
  278. if (pseudo_class.argument_selector_list.is_empty()) {
  279. s.append(':');
  280. s.append(pseudo_class_name(pseudo_class.type));
  281. } else {
  282. s.append(':');
  283. s.append(pseudo_class_name(pseudo_class.type));
  284. s.append('(');
  285. s.append(serialize_a_group_of_selectors(pseudo_class.argument_selector_list));
  286. s.append(')');
  287. }
  288. }
  289. // If the pseudo-class does not accept arguments append ":" (U+003A), followed by the name of the pseudo-class, to s.
  290. else if (metadata.is_valid_as_identifier) {
  291. s.append(':');
  292. s.append(pseudo_class_name(pseudo_class.type));
  293. }
  294. // Otherwise, append ":" (U+003A), followed by the name of the pseudo-class, followed by "(" (U+0028),
  295. // followed by the value of the pseudo-class argument(s) determined as per below, followed by ")" (U+0029), to s.
  296. else {
  297. s.append(':');
  298. s.append(pseudo_class_name(pseudo_class.type));
  299. s.append('(');
  300. if (pseudo_class.type == PseudoClass::NthChild
  301. || pseudo_class.type == PseudoClass::NthLastChild
  302. || pseudo_class.type == PseudoClass::NthOfType
  303. || pseudo_class.type == PseudoClass::NthLastOfType) {
  304. // The result of serializing the value using the rules to serialize an <an+b> value.
  305. s.append(pseudo_class.nth_child_pattern.serialize());
  306. } else if (pseudo_class.type == PseudoClass::Not
  307. || pseudo_class.type == PseudoClass::Is
  308. || pseudo_class.type == PseudoClass::Where) {
  309. // The result of serializing the value using the rules for serializing a group of selectors.
  310. // NOTE: `:is()` and `:where()` aren't in the spec for this yet, but it should be!
  311. s.append(serialize_a_group_of_selectors(pseudo_class.argument_selector_list));
  312. } else if (pseudo_class.type == PseudoClass::Lang) {
  313. // The serialization of a comma-separated list of each argument’s serialization as a string, preserving relative order.
  314. s.join(", "sv, pseudo_class.languages);
  315. }
  316. s.append(')');
  317. }
  318. break;
  319. }
  320. case Selector::SimpleSelector::Type::PseudoElement:
  321. // Note: Pseudo-elements are dealt with in Selector::serialize()
  322. break;
  323. case Type::Nesting:
  324. // AD-HOC: Not in spec yet.
  325. s.append('&');
  326. break;
  327. }
  328. return MUST(s.to_string());
  329. }
  330. // https://www.w3.org/TR/cssom/#serialize-a-selector
  331. String Selector::serialize() const
  332. {
  333. StringBuilder s;
  334. // To serialize a selector let s be the empty string, run the steps below for each part of the chain of the selector, and finally return s:
  335. for (size_t i = 0; i < compound_selectors().size(); ++i) {
  336. auto const& compound_selector = compound_selectors()[i];
  337. // 1. If there is only one simple selector in the compound selectors which is a universal selector, append the result of serializing the universal selector to s.
  338. if (compound_selector.simple_selectors.size() == 1
  339. && compound_selector.simple_selectors.first().type == Selector::SimpleSelector::Type::Universal) {
  340. s.append(compound_selector.simple_selectors.first().serialize());
  341. }
  342. // 2. Otherwise, for each simple selector in the compound selectors that is not a universal selector
  343. // of which the namespace prefix maps to a namespace that is not the default namespace
  344. // serialize the simple selector and append the result to s.
  345. else {
  346. for (auto& simple_selector : compound_selector.simple_selectors) {
  347. if (simple_selector.type == SimpleSelector::Type::Universal) {
  348. auto qualified_name = simple_selector.qualified_name();
  349. if (qualified_name.namespace_type == SimpleSelector::QualifiedName::NamespaceType::Default)
  350. continue;
  351. // FIXME: I *think* if we have a namespace prefix that happens to equal the same as the default namespace,
  352. // we also should skip it. But we don't have access to that here. eg:
  353. // <style>
  354. // @namespace "http://example";
  355. // @namespace foo "http://example";
  356. // foo|*.bar { } /* This would skip the `foo|*` when serializing. */
  357. // </style>
  358. }
  359. s.append(simple_selector.serialize());
  360. }
  361. }
  362. // 3. If this is not the last part of the chain of the selector append a single SPACE (U+0020),
  363. // followed by the combinator ">", "+", "~", ">>", "||", as appropriate, followed by another
  364. // single SPACE (U+0020) if the combinator was not whitespace, to s.
  365. if (i != compound_selectors().size() - 1) {
  366. s.append(' ');
  367. // Note: The combinator that appears between parts `i` and `i+1` appears with the `i+1` selector,
  368. // so we have to check that one.
  369. switch (compound_selectors()[i + 1].combinator) {
  370. case Selector::Combinator::ImmediateChild:
  371. s.append("> "sv);
  372. break;
  373. case Selector::Combinator::NextSibling:
  374. s.append("+ "sv);
  375. break;
  376. case Selector::Combinator::SubsequentSibling:
  377. s.append("~ "sv);
  378. break;
  379. case Selector::Combinator::Column:
  380. s.append("|| "sv);
  381. break;
  382. default:
  383. break;
  384. }
  385. } else {
  386. // 4. If this is the last part of the chain of the selector and there is a pseudo-element,
  387. // append "::" followed by the name of the pseudo-element, to s.
  388. if (compound_selector.simple_selectors.last().type == Selector::SimpleSelector::Type::PseudoElement) {
  389. s.append("::"sv);
  390. s.append(compound_selector.simple_selectors.last().pseudo_element().name());
  391. }
  392. }
  393. }
  394. return MUST(s.to_string());
  395. }
  396. // https://www.w3.org/TR/cssom/#serialize-a-group-of-selectors
  397. String serialize_a_group_of_selectors(SelectorList const& selectors)
  398. {
  399. // To serialize a group of selectors serialize each selector in the group of selectors and then serialize a comma-separated list of these serializations.
  400. return MUST(String::join(", "sv, selectors));
  401. }
  402. StringView Selector::PseudoElement::name(Selector::PseudoElement::Type pseudo_element)
  403. {
  404. switch (pseudo_element) {
  405. case Selector::PseudoElement::Type::Before:
  406. return "before"sv;
  407. case Selector::PseudoElement::Type::After:
  408. return "after"sv;
  409. case Selector::PseudoElement::Type::FirstLine:
  410. return "first-line"sv;
  411. case Selector::PseudoElement::Type::FirstLetter:
  412. return "first-letter"sv;
  413. case Selector::PseudoElement::Type::Marker:
  414. return "marker"sv;
  415. case Selector::PseudoElement::Type::MeterBar:
  416. return "-webkit-meter-bar"sv;
  417. case Selector::PseudoElement::Type::MeterEvenLessGoodValue:
  418. return "-webkit-meter-even-less-good-value"sv;
  419. case Selector::PseudoElement::Type::MeterOptimumValue:
  420. return "-webkit-meter-optimum-value"sv;
  421. case Selector::PseudoElement::Type::MeterSuboptimumValue:
  422. return "-webkit-meter-suboptimum-value"sv;
  423. case Selector::PseudoElement::Type::ProgressBar:
  424. return "-webkit-progress-bar"sv;
  425. case Selector::PseudoElement::Type::ProgressValue:
  426. return "-webkit-progress-value"sv;
  427. case Selector::PseudoElement::Type::Placeholder:
  428. return "placeholder"sv;
  429. case Selector::PseudoElement::Type::Selection:
  430. return "selection"sv;
  431. case Selector::PseudoElement::Type::SliderRunnableTrack:
  432. return "-webkit-slider-runnable-track"sv;
  433. case Selector::PseudoElement::Type::SliderThumb:
  434. return "-webkit-slider-thumb"sv;
  435. case Selector::PseudoElement::Type::Backdrop:
  436. return "backdrop"sv;
  437. case Selector::PseudoElement::Type::KnownPseudoElementCount:
  438. break;
  439. case Selector::PseudoElement::Type::UnknownWebKit:
  440. VERIFY_NOT_REACHED();
  441. }
  442. VERIFY_NOT_REACHED();
  443. }
  444. Optional<Selector::PseudoElement> Selector::PseudoElement::from_string(FlyString const& name)
  445. {
  446. if (name.equals_ignoring_ascii_case("after"sv)) {
  447. return Selector::PseudoElement { Selector::PseudoElement::Type::After };
  448. } else if (name.equals_ignoring_ascii_case("before"sv)) {
  449. return Selector::PseudoElement { Selector::PseudoElement::Type::Before };
  450. } else if (name.equals_ignoring_ascii_case("first-letter"sv)) {
  451. return Selector::PseudoElement { Selector::PseudoElement::Type::FirstLetter };
  452. } else if (name.equals_ignoring_ascii_case("first-line"sv)) {
  453. return Selector::PseudoElement { Selector::PseudoElement::Type::FirstLine };
  454. } else if (name.equals_ignoring_ascii_case("marker"sv)) {
  455. return Selector::PseudoElement { Selector::PseudoElement::Type::Marker };
  456. } else if (name.equals_ignoring_ascii_case("-webkit-meter-bar"sv)) {
  457. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterBar };
  458. } else if (name.equals_ignoring_ascii_case("-webkit-meter-even-less-good-value"sv)) {
  459. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterEvenLessGoodValue };
  460. } else if (name.equals_ignoring_ascii_case("-webkit-meter-optimum-value"sv)) {
  461. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterOptimumValue };
  462. } else if (name.equals_ignoring_ascii_case("-webkit-meter-suboptimum-value"sv)) {
  463. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterSuboptimumValue };
  464. } else if (name.equals_ignoring_ascii_case("-webkit-progress-bar"sv)) {
  465. return Selector::PseudoElement { Selector::PseudoElement::Type::ProgressBar };
  466. } else if (name.equals_ignoring_ascii_case("-webkit-progress-value"sv)) {
  467. return Selector::PseudoElement { Selector::PseudoElement::Type::ProgressValue };
  468. } else if (name.equals_ignoring_ascii_case("placeholder"sv)) {
  469. return Selector::PseudoElement { Selector::PseudoElement::Type::Placeholder };
  470. } else if (name.equals_ignoring_ascii_case("selection"sv)) {
  471. return Selector::PseudoElement { Selector::PseudoElement::Type::Selection };
  472. } else if (name.equals_ignoring_ascii_case("backdrop"sv)) {
  473. return Selector::PseudoElement { Selector::PseudoElement::Type::Backdrop };
  474. } else if (name.equals_ignoring_ascii_case("-webkit-slider-runnable-track"sv)) {
  475. return Selector::PseudoElement { Selector::PseudoElement::Type::SliderRunnableTrack };
  476. } else if (name.equals_ignoring_ascii_case("-webkit-slider-thumb"sv)) {
  477. return Selector::PseudoElement { Selector::PseudoElement::Type::SliderThumb };
  478. }
  479. return {};
  480. }
  481. NonnullRefPtr<Selector> Selector::relative_to(SimpleSelector const& parent) const
  482. {
  483. // To make us relative to the parent, prepend it to the list of compound selectors,
  484. // and ensure the next compound selector starts with a combinator.
  485. Vector<CompoundSelector> copied_compound_selectors;
  486. copied_compound_selectors.ensure_capacity(compound_selectors().size() + 1);
  487. copied_compound_selectors.empend(CompoundSelector { .simple_selectors = { parent } });
  488. bool first = true;
  489. for (auto compound_selector : compound_selectors()) {
  490. if (first) {
  491. if (compound_selector.combinator == Combinator::None)
  492. compound_selector.combinator = Combinator::Descendant;
  493. first = false;
  494. }
  495. copied_compound_selectors.append(move(compound_selector));
  496. }
  497. return Selector::create(move(copied_compound_selectors));
  498. }
  499. NonnullRefPtr<Selector> Selector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
  500. {
  501. if (!contains_the_nesting_selector())
  502. return *this;
  503. Vector<CompoundSelector> absolutized_compound_selectors;
  504. absolutized_compound_selectors.ensure_capacity(m_compound_selectors.size());
  505. for (auto const& compound_selector : m_compound_selectors)
  506. absolutized_compound_selectors.append(compound_selector.absolutized(selector_for_nesting));
  507. return Selector::create(move(absolutized_compound_selectors));
  508. }
  509. Selector::CompoundSelector Selector::CompoundSelector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
  510. {
  511. // TODO: Cache if it contains the nesting selector?
  512. Vector<SimpleSelector> absolutized_simple_selectors;
  513. absolutized_simple_selectors.ensure_capacity(simple_selectors.size());
  514. for (auto const& simple_selector : simple_selectors)
  515. absolutized_simple_selectors.append(simple_selector.absolutized(selector_for_nesting));
  516. return CompoundSelector {
  517. .combinator = this->combinator,
  518. .simple_selectors = absolutized_simple_selectors,
  519. };
  520. }
  521. Selector::SimpleSelector Selector::SimpleSelector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
  522. {
  523. switch (type) {
  524. case Type::Nesting:
  525. // Nesting selectors get replaced directly.
  526. return selector_for_nesting;
  527. case Type::PseudoClass: {
  528. // Pseudo-classes may contain other selectors, so we need to absolutize them.
  529. // Copy the PseudoClassSelector, and then replace its argument selector list.
  530. auto pseudo_class = this->pseudo_class();
  531. if (!pseudo_class.argument_selector_list.is_empty()) {
  532. SelectorList new_selector_list;
  533. new_selector_list.ensure_capacity(pseudo_class.argument_selector_list.size());
  534. for (auto const& argument_selector : pseudo_class.argument_selector_list)
  535. new_selector_list.append(argument_selector->absolutized(selector_for_nesting));
  536. pseudo_class.argument_selector_list = move(new_selector_list);
  537. }
  538. return SimpleSelector {
  539. .type = Type::PseudoClass,
  540. .value = move(pseudo_class),
  541. };
  542. }
  543. case Type::Universal:
  544. case Type::TagName:
  545. case Type::Id:
  546. case Type::Class:
  547. case Type::Attribute:
  548. case Type::PseudoElement:
  549. // Everything else isn't affected
  550. return *this;
  551. }
  552. VERIFY_NOT_REACHED();
  553. }
  554. }