Selector.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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. // "The specificity of the nesting selector is equal to the largest specificity among the complex selectors in the parent style rule’s selector list (identical to the behavior of :is()), or zero if no such selector list exists."
  168. // - https://drafts.csswg.org/css-nesting/#ref-for-specificity
  169. // The parented case is handled by replacing & with :is().
  170. // So if we got here, the specificity is 0.
  171. break;
  172. }
  173. }
  174. }
  175. // Due to storage limitations, implementations may have limitations on the size of A, B, or C.
  176. // If so, values higher than the limit must be clamped to that limit, and not overflow.
  177. m_specificity = (min(ids, 0xff) << ids_shift)
  178. + (min(classes, 0xff) << classes_shift)
  179. + (min(tag_names, 0xff) << tag_names_shift);
  180. return *m_specificity;
  181. }
  182. // https://www.w3.org/TR/cssom/#serialize-a-simple-selector
  183. String Selector::SimpleSelector::serialize() const
  184. {
  185. StringBuilder s;
  186. switch (type) {
  187. case Selector::SimpleSelector::Type::TagName:
  188. case Selector::SimpleSelector::Type::Universal: {
  189. auto qualified_name = this->qualified_name();
  190. // 1. If the namespace prefix maps to a namespace that is not the default namespace and is not the null
  191. // namespace (not in a namespace) append the serialization of the namespace prefix as an identifier,
  192. // followed by a "|" (U+007C) to s.
  193. if (qualified_name.namespace_type == QualifiedName::NamespaceType::Named) {
  194. serialize_an_identifier(s, qualified_name.namespace_);
  195. s.append('|');
  196. }
  197. // 2. If the namespace prefix maps to a namespace that is the null namespace (not in a namespace)
  198. // append "|" (U+007C) to s.
  199. if (qualified_name.namespace_type == QualifiedName::NamespaceType::None)
  200. s.append('|');
  201. // 3. If this is a type selector append the serialization of the element name as an identifier to s.
  202. if (type == Selector::SimpleSelector::Type::TagName)
  203. serialize_an_identifier(s, qualified_name.name.name);
  204. // 4. If this is a universal selector append "*" (U+002A) to s.
  205. if (type == Selector::SimpleSelector::Type::Universal)
  206. s.append('*');
  207. break;
  208. }
  209. case Selector::SimpleSelector::Type::Attribute: {
  210. auto& attribute = this->attribute();
  211. // 1. Append "[" (U+005B) to s.
  212. s.append('[');
  213. // 2. If the namespace prefix maps to a namespace that is not the null namespace (not in a namespace)
  214. // append the serialization of the namespace prefix as an identifier, followed by a "|" (U+007C) to s.
  215. if (attribute.qualified_name.namespace_type == QualifiedName::NamespaceType::Named) {
  216. serialize_an_identifier(s, attribute.qualified_name.namespace_);
  217. s.append('|');
  218. }
  219. // 3. Append the serialization of the attribute name as an identifier to s.
  220. serialize_an_identifier(s, attribute.qualified_name.name.name);
  221. // 4. If there is an attribute value specified, append "=", "~=", "|=", "^=", "$=", or "*=" as appropriate (depending on the type of attribute selector),
  222. // followed by the serialization of the attribute value as a string, to s.
  223. if (!attribute.value.is_empty()) {
  224. switch (attribute.match_type) {
  225. case Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch:
  226. s.append("="sv);
  227. break;
  228. case Selector::SimpleSelector::Attribute::MatchType::ContainsWord:
  229. s.append("~="sv);
  230. break;
  231. case Selector::SimpleSelector::Attribute::MatchType::ContainsString:
  232. s.append("*="sv);
  233. break;
  234. case Selector::SimpleSelector::Attribute::MatchType::StartsWithSegment:
  235. s.append("|="sv);
  236. break;
  237. case Selector::SimpleSelector::Attribute::MatchType::StartsWithString:
  238. s.append("^="sv);
  239. break;
  240. case Selector::SimpleSelector::Attribute::MatchType::EndsWithString:
  241. s.append("$="sv);
  242. break;
  243. default:
  244. break;
  245. }
  246. serialize_a_string(s, attribute.value);
  247. }
  248. // 5. If the attribute selector has the case-insensitivity flag present, append " i" (U+0020 U+0069) to s.
  249. // If the attribute selector has the case-insensitivity flag present, append " s" (U+0020 U+0073) to s.
  250. // (the line just above is an addition to CSS OM to match Selectors Level 4 last draft)
  251. switch (attribute.case_type) {
  252. case Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch:
  253. s.append(" i"sv);
  254. break;
  255. case Selector::SimpleSelector::Attribute::CaseType::CaseSensitiveMatch:
  256. s.append(" s"sv);
  257. break;
  258. default:
  259. break;
  260. }
  261. // 6. Append "]" (U+005D) to s.
  262. s.append(']');
  263. break;
  264. }
  265. case Selector::SimpleSelector::Type::Class:
  266. // Append a "." (U+002E), followed by the serialization of the class name as an identifier to s.
  267. s.append('.');
  268. serialize_an_identifier(s, name());
  269. break;
  270. case Selector::SimpleSelector::Type::Id:
  271. // Append a "#" (U+0023), followed by the serialization of the ID as an identifier to s.
  272. s.append('#');
  273. serialize_an_identifier(s, name());
  274. break;
  275. case Selector::SimpleSelector::Type::PseudoClass: {
  276. auto& pseudo_class = this->pseudo_class();
  277. auto metadata = pseudo_class_metadata(pseudo_class.type);
  278. // HACK: `:host()` has both a function and a non-function form, so handle that first.
  279. // It's also not in the spec.
  280. if (pseudo_class.type == PseudoClass::Host) {
  281. if (pseudo_class.argument_selector_list.is_empty()) {
  282. s.append(':');
  283. s.append(pseudo_class_name(pseudo_class.type));
  284. } else {
  285. s.append(':');
  286. s.append(pseudo_class_name(pseudo_class.type));
  287. s.append('(');
  288. s.append(serialize_a_group_of_selectors(pseudo_class.argument_selector_list));
  289. s.append(')');
  290. }
  291. }
  292. // If the pseudo-class does not accept arguments append ":" (U+003A), followed by the name of the pseudo-class, to s.
  293. else if (metadata.is_valid_as_identifier) {
  294. s.append(':');
  295. s.append(pseudo_class_name(pseudo_class.type));
  296. }
  297. // Otherwise, append ":" (U+003A), followed by the name of the pseudo-class, followed by "(" (U+0028),
  298. // followed by the value of the pseudo-class argument(s) determined as per below, followed by ")" (U+0029), to s.
  299. else {
  300. s.append(':');
  301. s.append(pseudo_class_name(pseudo_class.type));
  302. s.append('(');
  303. if (pseudo_class.type == PseudoClass::NthChild
  304. || pseudo_class.type == PseudoClass::NthLastChild
  305. || pseudo_class.type == PseudoClass::NthOfType
  306. || pseudo_class.type == PseudoClass::NthLastOfType) {
  307. // The result of serializing the value using the rules to serialize an <an+b> value.
  308. s.append(pseudo_class.nth_child_pattern.serialize());
  309. } else if (pseudo_class.type == PseudoClass::Not
  310. || pseudo_class.type == PseudoClass::Is
  311. || pseudo_class.type == PseudoClass::Where) {
  312. // The result of serializing the value using the rules for serializing a group of selectors.
  313. // NOTE: `:is()` and `:where()` aren't in the spec for this yet, but it should be!
  314. s.append(serialize_a_group_of_selectors(pseudo_class.argument_selector_list));
  315. } else if (pseudo_class.type == PseudoClass::Lang) {
  316. // The serialization of a comma-separated list of each argument’s serialization as a string, preserving relative order.
  317. s.join(", "sv, pseudo_class.languages);
  318. }
  319. s.append(')');
  320. }
  321. break;
  322. }
  323. case Selector::SimpleSelector::Type::PseudoElement:
  324. // Note: Pseudo-elements are dealt with in Selector::serialize()
  325. break;
  326. case Type::Nesting:
  327. // AD-HOC: Not in spec yet.
  328. s.append('&');
  329. break;
  330. }
  331. return MUST(s.to_string());
  332. }
  333. // https://www.w3.org/TR/cssom/#serialize-a-selector
  334. String Selector::serialize() const
  335. {
  336. StringBuilder s;
  337. // 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:
  338. for (size_t i = 0; i < compound_selectors().size(); ++i) {
  339. auto const& compound_selector = compound_selectors()[i];
  340. // 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.
  341. if (compound_selector.simple_selectors.size() == 1
  342. && compound_selector.simple_selectors.first().type == Selector::SimpleSelector::Type::Universal) {
  343. s.append(compound_selector.simple_selectors.first().serialize());
  344. }
  345. // 2. Otherwise, for each simple selector in the compound selectors that is not a universal selector
  346. // of which the namespace prefix maps to a namespace that is not the default namespace
  347. // serialize the simple selector and append the result to s.
  348. else {
  349. for (auto& simple_selector : compound_selector.simple_selectors) {
  350. if (simple_selector.type == SimpleSelector::Type::Universal) {
  351. auto qualified_name = simple_selector.qualified_name();
  352. if (qualified_name.namespace_type == SimpleSelector::QualifiedName::NamespaceType::Default)
  353. continue;
  354. // FIXME: I *think* if we have a namespace prefix that happens to equal the same as the default namespace,
  355. // we also should skip it. But we don't have access to that here. eg:
  356. // <style>
  357. // @namespace "http://example";
  358. // @namespace foo "http://example";
  359. // foo|*.bar { } /* This would skip the `foo|*` when serializing. */
  360. // </style>
  361. }
  362. s.append(simple_selector.serialize());
  363. }
  364. }
  365. // 3. If this is not the last part of the chain of the selector append a single SPACE (U+0020),
  366. // followed by the combinator ">", "+", "~", ">>", "||", as appropriate, followed by another
  367. // single SPACE (U+0020) if the combinator was not whitespace, to s.
  368. if (i != compound_selectors().size() - 1) {
  369. s.append(' ');
  370. // Note: The combinator that appears between parts `i` and `i+1` appears with the `i+1` selector,
  371. // so we have to check that one.
  372. switch (compound_selectors()[i + 1].combinator) {
  373. case Selector::Combinator::ImmediateChild:
  374. s.append("> "sv);
  375. break;
  376. case Selector::Combinator::NextSibling:
  377. s.append("+ "sv);
  378. break;
  379. case Selector::Combinator::SubsequentSibling:
  380. s.append("~ "sv);
  381. break;
  382. case Selector::Combinator::Column:
  383. s.append("|| "sv);
  384. break;
  385. default:
  386. break;
  387. }
  388. } else {
  389. // 4. If this is the last part of the chain of the selector and there is a pseudo-element,
  390. // append "::" followed by the name of the pseudo-element, to s.
  391. if (compound_selector.simple_selectors.last().type == Selector::SimpleSelector::Type::PseudoElement) {
  392. s.append("::"sv);
  393. s.append(compound_selector.simple_selectors.last().pseudo_element().name());
  394. }
  395. }
  396. }
  397. return MUST(s.to_string());
  398. }
  399. // https://www.w3.org/TR/cssom/#serialize-a-group-of-selectors
  400. String serialize_a_group_of_selectors(SelectorList const& selectors)
  401. {
  402. // To serialize a group of selectors serialize each selector in the group of selectors and then serialize a comma-separated list of these serializations.
  403. return MUST(String::join(", "sv, selectors));
  404. }
  405. StringView Selector::PseudoElement::name(Selector::PseudoElement::Type pseudo_element)
  406. {
  407. switch (pseudo_element) {
  408. case Selector::PseudoElement::Type::Before:
  409. return "before"sv;
  410. case Selector::PseudoElement::Type::After:
  411. return "after"sv;
  412. case Selector::PseudoElement::Type::FirstLine:
  413. return "first-line"sv;
  414. case Selector::PseudoElement::Type::FirstLetter:
  415. return "first-letter"sv;
  416. case Selector::PseudoElement::Type::Marker:
  417. return "marker"sv;
  418. case Selector::PseudoElement::Type::MeterBar:
  419. return "-webkit-meter-bar"sv;
  420. case Selector::PseudoElement::Type::MeterEvenLessGoodValue:
  421. return "-webkit-meter-even-less-good-value"sv;
  422. case Selector::PseudoElement::Type::MeterOptimumValue:
  423. return "-webkit-meter-optimum-value"sv;
  424. case Selector::PseudoElement::Type::MeterSuboptimumValue:
  425. return "-webkit-meter-suboptimum-value"sv;
  426. case Selector::PseudoElement::Type::ProgressBar:
  427. return "-webkit-progress-bar"sv;
  428. case Selector::PseudoElement::Type::ProgressValue:
  429. return "-webkit-progress-value"sv;
  430. case Selector::PseudoElement::Type::Placeholder:
  431. return "placeholder"sv;
  432. case Selector::PseudoElement::Type::Selection:
  433. return "selection"sv;
  434. case Selector::PseudoElement::Type::SliderRunnableTrack:
  435. return "-webkit-slider-runnable-track"sv;
  436. case Selector::PseudoElement::Type::SliderThumb:
  437. return "-webkit-slider-thumb"sv;
  438. case Selector::PseudoElement::Type::Backdrop:
  439. return "backdrop"sv;
  440. case Selector::PseudoElement::Type::KnownPseudoElementCount:
  441. break;
  442. case Selector::PseudoElement::Type::UnknownWebKit:
  443. VERIFY_NOT_REACHED();
  444. }
  445. VERIFY_NOT_REACHED();
  446. }
  447. Optional<Selector::PseudoElement> Selector::PseudoElement::from_string(FlyString const& name)
  448. {
  449. if (name.equals_ignoring_ascii_case("after"sv)) {
  450. return Selector::PseudoElement { Selector::PseudoElement::Type::After };
  451. } else if (name.equals_ignoring_ascii_case("before"sv)) {
  452. return Selector::PseudoElement { Selector::PseudoElement::Type::Before };
  453. } else if (name.equals_ignoring_ascii_case("first-letter"sv)) {
  454. return Selector::PseudoElement { Selector::PseudoElement::Type::FirstLetter };
  455. } else if (name.equals_ignoring_ascii_case("first-line"sv)) {
  456. return Selector::PseudoElement { Selector::PseudoElement::Type::FirstLine };
  457. } else if (name.equals_ignoring_ascii_case("marker"sv)) {
  458. return Selector::PseudoElement { Selector::PseudoElement::Type::Marker };
  459. } else if (name.equals_ignoring_ascii_case("-webkit-meter-bar"sv)) {
  460. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterBar };
  461. } else if (name.equals_ignoring_ascii_case("-webkit-meter-even-less-good-value"sv)) {
  462. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterEvenLessGoodValue };
  463. } else if (name.equals_ignoring_ascii_case("-webkit-meter-optimum-value"sv)) {
  464. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterOptimumValue };
  465. } else if (name.equals_ignoring_ascii_case("-webkit-meter-suboptimum-value"sv)) {
  466. return Selector::PseudoElement { Selector::PseudoElement::Type::MeterSuboptimumValue };
  467. } else if (name.equals_ignoring_ascii_case("-webkit-progress-bar"sv)) {
  468. return Selector::PseudoElement { Selector::PseudoElement::Type::ProgressBar };
  469. } else if (name.equals_ignoring_ascii_case("-webkit-progress-value"sv)) {
  470. return Selector::PseudoElement { Selector::PseudoElement::Type::ProgressValue };
  471. } else if (name.equals_ignoring_ascii_case("placeholder"sv)) {
  472. return Selector::PseudoElement { Selector::PseudoElement::Type::Placeholder };
  473. } else if (name.equals_ignoring_ascii_case("selection"sv)) {
  474. return Selector::PseudoElement { Selector::PseudoElement::Type::Selection };
  475. } else if (name.equals_ignoring_ascii_case("backdrop"sv)) {
  476. return Selector::PseudoElement { Selector::PseudoElement::Type::Backdrop };
  477. } else if (name.equals_ignoring_ascii_case("-webkit-slider-runnable-track"sv)) {
  478. return Selector::PseudoElement { Selector::PseudoElement::Type::SliderRunnableTrack };
  479. } else if (name.equals_ignoring_ascii_case("-webkit-slider-thumb"sv)) {
  480. return Selector::PseudoElement { Selector::PseudoElement::Type::SliderThumb };
  481. }
  482. return {};
  483. }
  484. NonnullRefPtr<Selector> Selector::relative_to(SimpleSelector const& parent) const
  485. {
  486. // To make us relative to the parent, prepend it to the list of compound selectors,
  487. // and ensure the next compound selector starts with a combinator.
  488. Vector<CompoundSelector> copied_compound_selectors;
  489. copied_compound_selectors.ensure_capacity(compound_selectors().size() + 1);
  490. copied_compound_selectors.empend(CompoundSelector { .simple_selectors = { parent } });
  491. bool first = true;
  492. for (auto compound_selector : compound_selectors()) {
  493. if (first) {
  494. if (compound_selector.combinator == Combinator::None)
  495. compound_selector.combinator = Combinator::Descendant;
  496. first = false;
  497. }
  498. copied_compound_selectors.append(move(compound_selector));
  499. }
  500. return Selector::create(move(copied_compound_selectors));
  501. }
  502. NonnullRefPtr<Selector> Selector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
  503. {
  504. if (!contains_the_nesting_selector())
  505. return *this;
  506. Vector<CompoundSelector> absolutized_compound_selectors;
  507. absolutized_compound_selectors.ensure_capacity(m_compound_selectors.size());
  508. for (auto const& compound_selector : m_compound_selectors)
  509. absolutized_compound_selectors.append(compound_selector.absolutized(selector_for_nesting));
  510. return Selector::create(move(absolutized_compound_selectors));
  511. }
  512. Selector::CompoundSelector Selector::CompoundSelector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
  513. {
  514. // TODO: Cache if it contains the nesting selector?
  515. Vector<SimpleSelector> absolutized_simple_selectors;
  516. absolutized_simple_selectors.ensure_capacity(simple_selectors.size());
  517. for (auto const& simple_selector : simple_selectors)
  518. absolutized_simple_selectors.append(simple_selector.absolutized(selector_for_nesting));
  519. return CompoundSelector {
  520. .combinator = this->combinator,
  521. .simple_selectors = absolutized_simple_selectors,
  522. };
  523. }
  524. Selector::SimpleSelector Selector::SimpleSelector::absolutized(Selector::SimpleSelector const& selector_for_nesting) const
  525. {
  526. switch (type) {
  527. case Type::Nesting:
  528. // Nesting selectors get replaced directly.
  529. return selector_for_nesting;
  530. case Type::PseudoClass: {
  531. // Pseudo-classes may contain other selectors, so we need to absolutize them.
  532. // Copy the PseudoClassSelector, and then replace its argument selector list.
  533. auto pseudo_class = this->pseudo_class();
  534. if (!pseudo_class.argument_selector_list.is_empty()) {
  535. SelectorList new_selector_list;
  536. new_selector_list.ensure_capacity(pseudo_class.argument_selector_list.size());
  537. for (auto const& argument_selector : pseudo_class.argument_selector_list)
  538. new_selector_list.append(argument_selector->absolutized(selector_for_nesting));
  539. pseudo_class.argument_selector_list = move(new_selector_list);
  540. }
  541. return SimpleSelector {
  542. .type = Type::PseudoClass,
  543. .value = move(pseudo_class),
  544. };
  545. }
  546. case Type::Universal:
  547. case Type::TagName:
  548. case Type::Id:
  549. case Type::Class:
  550. case Type::Attribute:
  551. case Type::PseudoElement:
  552. // Everything else isn't affected
  553. return *this;
  554. }
  555. VERIFY_NOT_REACHED();
  556. }
  557. SelectorList adapt_nested_relative_selector_list(SelectorList const& selectors)
  558. {
  559. // "Nested style rules differ from non-nested rules in the following ways:
  560. // - A nested style rule accepts a <relative-selector-list> as its prelude (rather than just a <selector-list>).
  561. // Any relative selectors are relative to the elements represented by the nesting selector.
  562. // - If a selector in the <relative-selector-list> does not start with a combinator but does contain the nesting
  563. // selector, it is interpreted as a non-relative selector."
  564. // https://drafts.csswg.org/css-nesting-1/#syntax
  565. // NOTE: We already parsed the selectors as a <relative-selector-list>
  566. // Nested relative selectors get a `&` inserted at the beginning.
  567. // This is, handily, how the spec wants them serialized:
  568. // "When serializing a relative selector in a nested style rule, the selector must be absolutized,
  569. // with the implied nesting selector inserted."
  570. // - https://drafts.csswg.org/css-nesting-1/#cssom
  571. CSS::SelectorList new_list;
  572. new_list.ensure_capacity(selectors.size());
  573. for (auto const& selector : selectors) {
  574. auto first_combinator = selector->compound_selectors().first().combinator;
  575. if (!first_is_one_of(first_combinator, CSS::Selector::Combinator::None, CSS::Selector::Combinator::Descendant)
  576. || !selector->contains_the_nesting_selector()) {
  577. new_list.append(selector->relative_to(CSS::Selector::SimpleSelector { .type = CSS::Selector::SimpleSelector::Type::Nesting }));
  578. } else if (first_combinator == CSS::Selector::Combinator::Descendant) {
  579. // Replace leading descendant combinator (whitespace) with none, because we're not actually relative.
  580. auto copied_compound_selectors = selector->compound_selectors();
  581. copied_compound_selectors.first().combinator = CSS::Selector::Combinator::None;
  582. new_list.append(CSS::Selector::create(move(copied_compound_selectors)));
  583. } else {
  584. new_list.append(selector);
  585. }
  586. }
  587. return new_list;
  588. }
  589. }