cfsolve 0.1.0-x86_64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6 -0
  3. data/LICENSE +21 -0
  4. data/README.md +66 -0
  5. data/THIRD_PARTY_LICENSES/Inflector-0.11.4/LICENSE.md +22 -0
  6. data/THIRD_PARTY_LICENSES/README.md +761 -0
  7. data/THIRD_PARTY_LICENSES/adler2-2.0.1/LICENSE-0BSD +12 -0
  8. data/THIRD_PARTY_LICENSES/adler2-2.0.1/LICENSE-APACHE +201 -0
  9. data/THIRD_PARTY_LICENSES/adler2-2.0.1/LICENSE-MIT +23 -0
  10. data/THIRD_PARTY_LICENSES/ahash-0.8.12/LICENSE-APACHE +201 -0
  11. data/THIRD_PARTY_LICENSES/ahash-0.8.12/LICENSE-MIT +25 -0
  12. data/THIRD_PARTY_LICENSES/aho-corasick-1.1.4/COPYING +3 -0
  13. data/THIRD_PARTY_LICENSES/aho-corasick-1.1.4/LICENSE-MIT +21 -0
  14. data/THIRD_PARTY_LICENSES/alloc-no-stdlib-2.0.4/LICENSE +12 -0
  15. data/THIRD_PARTY_LICENSES/alloc-stdlib-0.2.4/LICENSE +12 -0
  16. data/THIRD_PARTY_LICENSES/allocator-api2-0.2.21/LICENSE-APACHE +176 -0
  17. data/THIRD_PARTY_LICENSES/allocator-api2-0.2.21/LICENSE-MIT +23 -0
  18. data/THIRD_PARTY_LICENSES/android_system_properties-0.1.5/LICENSE-APACHE +13 -0
  19. data/THIRD_PARTY_LICENSES/android_system_properties-0.1.5/LICENSE-MIT +20 -0
  20. data/THIRD_PARTY_LICENSES/anyhow-1.0.104/LICENSE-APACHE +176 -0
  21. data/THIRD_PARTY_LICENSES/anyhow-1.0.104/LICENSE-MIT +23 -0
  22. data/THIRD_PARTY_LICENSES/arrayvec-0.7.6/LICENSE-APACHE +201 -0
  23. data/THIRD_PARTY_LICENSES/arrayvec-0.7.6/LICENSE-MIT +25 -0
  24. data/THIRD_PARTY_LICENSES/ascii-1.1.0/LICENSE-APACHE +201 -0
  25. data/THIRD_PARTY_LICENSES/ascii-1.1.0/LICENSE-MIT +22 -0
  26. data/THIRD_PARTY_LICENSES/ast_node-5.0.0/LICENSE +201 -0
  27. data/THIRD_PARTY_LICENSES/async-compression-0.4.45/LICENSE-APACHE +201 -0
  28. data/THIRD_PARTY_LICENSES/async-compression-0.4.45/LICENSE-MIT +21 -0
  29. data/THIRD_PARTY_LICENSES/atomic-waker-1.1.2/LICENSE-APACHE +201 -0
  30. data/THIRD_PARTY_LICENSES/atomic-waker-1.1.2/LICENSE-MIT +23 -0
  31. data/THIRD_PARTY_LICENSES/atomic-waker-1.1.2/LICENSE-THIRD-PARTY +45 -0
  32. data/THIRD_PARTY_LICENSES/autocfg-1.5.0/LICENSE-APACHE +201 -0
  33. data/THIRD_PARTY_LICENSES/autocfg-1.5.0/LICENSE-MIT +25 -0
  34. data/THIRD_PARTY_LICENSES/base64-0.22.1/LICENSE-APACHE +201 -0
  35. data/THIRD_PARTY_LICENSES/base64-0.22.1/LICENSE-MIT +21 -0
  36. data/THIRD_PARTY_LICENSES/base64-simd-0.8.0/LICENSE +21 -0
  37. data/THIRD_PARTY_LICENSES/better_scoped_tls-1.0.1/LICENSE +201 -0
  38. data/THIRD_PARTY_LICENSES/bindgen-0.72.1/LICENSE +29 -0
  39. data/THIRD_PARTY_LICENSES/bitflags-2.13.1/LICENSE-APACHE +201 -0
  40. data/THIRD_PARTY_LICENSES/bitflags-2.13.1/LICENSE-MIT +25 -0
  41. data/THIRD_PARTY_LICENSES/bitvec-1.0.1/LICENSE.txt +21 -0
  42. data/THIRD_PARTY_LICENSES/block-buffer-0.10.4/LICENSE-APACHE +201 -0
  43. data/THIRD_PARTY_LICENSES/block-buffer-0.10.4/LICENSE-MIT +25 -0
  44. data/THIRD_PARTY_LICENSES/brotli-8.0.4/LICENSE.BSD-3-Clause +12 -0
  45. data/THIRD_PARTY_LICENSES/brotli-8.0.4/LICENSE.MIT +19 -0
  46. data/THIRD_PARTY_LICENSES/brotli-decompressor-5.0.3/LICENSE +12 -0
  47. data/THIRD_PARTY_LICENSES/browserslist-data-0.1.4/LICENSE +21 -0
  48. data/THIRD_PARTY_LICENSES/browserslist-rs-0.19.0/LICENSE +21 -0
  49. data/THIRD_PARTY_LICENSES/bstr-1.12.1/COPYING +8 -0
  50. data/THIRD_PARTY_LICENSES/bstr-1.12.1/LICENSE-APACHE +201 -0
  51. data/THIRD_PARTY_LICENSES/bstr-1.12.1/LICENSE-MIT +21 -0
  52. data/THIRD_PARTY_LICENSES/btls-0.5.6/LICENSE +17 -0
  53. data/THIRD_PARTY_LICENSES/btls-sys-0.5.6/BORINGSSL-LICENSE +238 -0
  54. data/THIRD_PARTY_LICENSES/btls-sys-0.5.6/LICENSE-MIT +27 -0
  55. data/THIRD_PARTY_LICENSES/bumpalo-3.20.3/LICENSE-APACHE +201 -0
  56. data/THIRD_PARTY_LICENSES/bumpalo-3.20.3/LICENSE-MIT +25 -0
  57. data/THIRD_PARTY_LICENSES/bytes-1.12.1/LICENSE +25 -0
  58. data/THIRD_PARTY_LICENSES/bytes-str-0.2.7/LICENSE +202 -0
  59. data/THIRD_PARTY_LICENSES/camino-1.2.2/LICENSE-APACHE +201 -0
  60. data/THIRD_PARTY_LICENSES/camino-1.2.2/LICENSE-MIT +23 -0
  61. data/THIRD_PARTY_LICENSES/cargo-platform-0.1.9/LICENSE-APACHE +201 -0
  62. data/THIRD_PARTY_LICENSES/cargo-platform-0.1.9/LICENSE-MIT +23 -0
  63. data/THIRD_PARTY_LICENSES/cargo_metadata-0.19.2/LICENSE-MIT +23 -0
  64. data/THIRD_PARTY_LICENSES/castaway-0.2.4/LICENSE +21 -0
  65. data/THIRD_PARTY_LICENSES/cc-1.2.51/LICENSE-APACHE +201 -0
  66. data/THIRD_PARTY_LICENSES/cc-1.2.51/LICENSE-MIT +25 -0
  67. data/THIRD_PARTY_LICENSES/cexpr-0.6.0/LICENSE-APACHE +201 -0
  68. data/THIRD_PARTY_LICENSES/cexpr-0.6.0/LICENSE-MIT +25 -0
  69. data/THIRD_PARTY_LICENSES/cfg-if-1.0.4/LICENSE-APACHE +201 -0
  70. data/THIRD_PARTY_LICENSES/cfg-if-1.0.4/LICENSE-MIT +25 -0
  71. data/THIRD_PARTY_LICENSES/cfsolve/LICENSE +21 -0
  72. data/THIRD_PARTY_LICENSES/cfsolve-0.1.0/LICENSE +21 -0
  73. data/THIRD_PARTY_LICENSES/chrono-0.4.42/LICENSE.txt +240 -0
  74. data/THIRD_PARTY_LICENSES/clang-sys-1.9.1/LICENSE.txt +202 -0
  75. data/THIRD_PARTY_LICENSES/cmake-0.1.58/LICENSE-APACHE +201 -0
  76. data/THIRD_PARTY_LICENSES/cmake-0.1.58/LICENSE-MIT +25 -0
  77. data/THIRD_PARTY_LICENSES/compact_str-0.7.1/LICENSE +21 -0
  78. data/THIRD_PARTY_LICENSES/compression-codecs-0.4.40/LICENSE-APACHE +201 -0
  79. data/THIRD_PARTY_LICENSES/compression-codecs-0.4.40/LICENSE-MIT +21 -0
  80. data/THIRD_PARTY_LICENSES/compression-core-0.4.33/LICENSE-APACHE +201 -0
  81. data/THIRD_PARTY_LICENSES/compression-core-0.4.33/LICENSE-MIT +21 -0
  82. data/THIRD_PARTY_LICENSES/cookie-0.18.2/LICENSE-APACHE +202 -0
  83. data/THIRD_PARTY_LICENSES/cookie-0.18.2/LICENSE-MIT +26 -0
  84. data/THIRD_PARTY_LICENSES/core-foundation-sys-0.8.7/LICENSE-APACHE +201 -0
  85. data/THIRD_PARTY_LICENSES/core-foundation-sys-0.8.7/LICENSE-MIT +25 -0
  86. data/THIRD_PARTY_LICENSES/cpufeatures-0.2.17/LICENSE-APACHE +201 -0
  87. data/THIRD_PARTY_LICENSES/cpufeatures-0.2.17/LICENSE-MIT +25 -0
  88. data/THIRD_PARTY_LICENSES/crc32fast-1.5.1/LICENSE-APACHE +202 -0
  89. data/THIRD_PARTY_LICENSES/crc32fast-1.5.1/LICENSE-MIT +21 -0
  90. data/THIRD_PARTY_LICENSES/crypto-common-0.1.7/LICENSE-APACHE +201 -0
  91. data/THIRD_PARTY_LICENSES/crypto-common-0.1.7/LICENSE-MIT +25 -0
  92. data/THIRD_PARTY_LICENSES/cssparser-0.37.0/LICENSE +373 -0
  93. data/THIRD_PARTY_LICENSES/cssparser-macros-0.7.1/LICENSE +373 -0
  94. data/THIRD_PARTY_LICENSES/darling-0.20.11/LICENSE +21 -0
  95. data/THIRD_PARTY_LICENSES/darling_core-0.20.11/LICENSE +21 -0
  96. data/THIRD_PARTY_LICENSES/darling_macro-0.20.11/LICENSE +21 -0
  97. data/THIRD_PARTY_LICENSES/dashmap-5.5.3/LICENSE +21 -0
  98. data/THIRD_PARTY_LICENSES/data-encoding-2.9.0/LICENSE +22 -0
  99. data/THIRD_PARTY_LICENSES/debugid-0.8.0/LICENSE +201 -0
  100. data/THIRD_PARTY_LICENSES/deranged-0.5.8/LICENSE-Apache +202 -0
  101. data/THIRD_PARTY_LICENSES/deranged-0.5.8/LICENSE-MIT +19 -0
  102. data/THIRD_PARTY_LICENSES/derive_builder-0.20.2/LICENSE-APACHE +202 -0
  103. data/THIRD_PARTY_LICENSES/derive_builder-0.20.2/LICENSE-MIT +21 -0
  104. data/THIRD_PARTY_LICENSES/derive_builder_core-0.20.2/LICENSE-APACHE +202 -0
  105. data/THIRD_PARTY_LICENSES/derive_builder_core-0.20.2/LICENSE-MIT +21 -0
  106. data/THIRD_PARTY_LICENSES/derive_builder_macro-0.20.2/LICENSE-APACHE +202 -0
  107. data/THIRD_PARTY_LICENSES/derive_builder_macro-0.20.2/LICENSE-MIT +21 -0
  108. data/THIRD_PARTY_LICENSES/derive_more-2.1.1/LICENSE +21 -0
  109. data/THIRD_PARTY_LICENSES/derive_more-impl-2.1.1/LICENSE +21 -0
  110. data/THIRD_PARTY_LICENSES/digest-0.10.7/LICENSE-APACHE +201 -0
  111. data/THIRD_PARTY_LICENSES/digest-0.10.7/LICENSE-MIT +25 -0
  112. data/THIRD_PARTY_LICENSES/displaydoc-0.2.5/LICENSE-APACHE +201 -0
  113. data/THIRD_PARTY_LICENSES/displaydoc-0.2.5/LICENSE-MIT +23 -0
  114. data/THIRD_PARTY_LICENSES/dtoa-1.0.11/LICENSE-APACHE +176 -0
  115. data/THIRD_PARTY_LICENSES/dtoa-1.0.11/LICENSE-MIT +23 -0
  116. data/THIRD_PARTY_LICENSES/dtoa-short-0.3.5/LICENSE +373 -0
  117. data/THIRD_PARTY_LICENSES/ego-tree-0.11.0/LICENSE +14 -0
  118. data/THIRD_PARTY_LICENSES/either-1.15.0/LICENSE-APACHE +201 -0
  119. data/THIRD_PARTY_LICENSES/either-1.15.0/LICENSE-MIT +25 -0
  120. data/THIRD_PARTY_LICENSES/equivalent-1.0.2/LICENSE-APACHE +201 -0
  121. data/THIRD_PARTY_LICENSES/equivalent-1.0.2/LICENSE-MIT +25 -0
  122. data/THIRD_PARTY_LICENSES/errno-0.3.14/LICENSE-APACHE +201 -0
  123. data/THIRD_PARTY_LICENSES/errno-0.3.14/LICENSE-MIT +25 -0
  124. data/THIRD_PARTY_LICENSES/fastrand-2.3.0/LICENSE-APACHE +201 -0
  125. data/THIRD_PARTY_LICENSES/fastrand-2.3.0/LICENSE-MIT +23 -0
  126. data/THIRD_PARTY_LICENSES/find-msvc-tools-0.1.6/LICENSE-APACHE +201 -0
  127. data/THIRD_PARTY_LICENSES/find-msvc-tools-0.1.6/LICENSE-MIT +25 -0
  128. data/THIRD_PARTY_LICENSES/fixedbitset-0.5.7/LICENSE-APACHE +201 -0
  129. data/THIRD_PARTY_LICENSES/fixedbitset-0.5.7/LICENSE-MIT +25 -0
  130. data/THIRD_PARTY_LICENSES/flate2-1.1.10/LICENSE-APACHE +201 -0
  131. data/THIRD_PARTY_LICENSES/flate2-1.1.10/LICENSE-MIT +25 -0
  132. data/THIRD_PARTY_LICENSES/fnv-1.0.7/LICENSE-APACHE +201 -0
  133. data/THIRD_PARTY_LICENSES/fnv-1.0.7/LICENSE-MIT +25 -0
  134. data/THIRD_PARTY_LICENSES/foldhash-0.1.5/LICENSE +19 -0
  135. data/THIRD_PARTY_LICENSES/foldhash-0.2.0/LICENSE +19 -0
  136. data/THIRD_PARTY_LICENSES/foreign-types-0.5.0/LICENSE-APACHE +202 -0
  137. data/THIRD_PARTY_LICENSES/foreign-types-0.5.0/LICENSE-MIT +19 -0
  138. data/THIRD_PARTY_LICENSES/foreign-types-macros-0.2.4/LICENSE-APACHE +202 -0
  139. data/THIRD_PARTY_LICENSES/foreign-types-macros-0.2.4/LICENSE-MIT +19 -0
  140. data/THIRD_PARTY_LICENSES/foreign-types-shared-0.3.1/LICENSE-APACHE +202 -0
  141. data/THIRD_PARTY_LICENSES/foreign-types-shared-0.3.1/LICENSE-MIT +19 -0
  142. data/THIRD_PARTY_LICENSES/form_urlencoded-1.2.2/LICENSE-APACHE +201 -0
  143. data/THIRD_PARTY_LICENSES/form_urlencoded-1.2.2/LICENSE-MIT +25 -0
  144. data/THIRD_PARTY_LICENSES/from_variant-3.0.0/LICENSE +201 -0
  145. data/THIRD_PARTY_LICENSES/fs_extra-1.3.0/LICENSE +21 -0
  146. data/THIRD_PARTY_LICENSES/fslock-0.2.1/LICENSE +21 -0
  147. data/THIRD_PARTY_LICENSES/funty-2.0.0/LICENSE.txt +21 -0
  148. data/THIRD_PARTY_LICENSES/futures-channel-0.3.34/LICENSE-APACHE +202 -0
  149. data/THIRD_PARTY_LICENSES/futures-channel-0.3.34/LICENSE-MIT +26 -0
  150. data/THIRD_PARTY_LICENSES/futures-core-0.3.34/LICENSE-APACHE +202 -0
  151. data/THIRD_PARTY_LICENSES/futures-core-0.3.34/LICENSE-MIT +26 -0
  152. data/THIRD_PARTY_LICENSES/futures-sink-0.3.34/LICENSE-APACHE +202 -0
  153. data/THIRD_PARTY_LICENSES/futures-sink-0.3.34/LICENSE-MIT +26 -0
  154. data/THIRD_PARTY_LICENSES/futures-task-0.3.34/LICENSE-APACHE +202 -0
  155. data/THIRD_PARTY_LICENSES/futures-task-0.3.34/LICENSE-MIT +26 -0
  156. data/THIRD_PARTY_LICENSES/futures-util-0.3.34/LICENSE-APACHE +202 -0
  157. data/THIRD_PARTY_LICENSES/futures-util-0.3.34/LICENSE-MIT +26 -0
  158. data/THIRD_PARTY_LICENSES/generic-array-0.14.7/LICENSE +21 -0
  159. data/THIRD_PARTY_LICENSES/getopts-0.2.24/LICENSE-APACHE +201 -0
  160. data/THIRD_PARTY_LICENSES/getopts-0.2.24/LICENSE-MIT +25 -0
  161. data/THIRD_PARTY_LICENSES/getrandom-0.3.4/LICENSE-APACHE +201 -0
  162. data/THIRD_PARTY_LICENSES/getrandom-0.3.4/LICENSE-MIT +26 -0
  163. data/THIRD_PARTY_LICENSES/getrandom-0.4.3/LICENSE-APACHE +201 -0
  164. data/THIRD_PARTY_LICENSES/getrandom-0.4.3/LICENSE-MIT +26 -0
  165. data/THIRD_PARTY_LICENSES/glob-0.3.3/LICENSE-APACHE +201 -0
  166. data/THIRD_PARTY_LICENSES/glob-0.3.3/LICENSE-MIT +25 -0
  167. data/THIRD_PARTY_LICENSES/globset-0.4.18/COPYING +3 -0
  168. data/THIRD_PARTY_LICENSES/globset-0.4.18/LICENSE-MIT +21 -0
  169. data/THIRD_PARTY_LICENSES/hashbrown-0.14.5/LICENSE-APACHE +201 -0
  170. data/THIRD_PARTY_LICENSES/hashbrown-0.14.5/LICENSE-MIT +25 -0
  171. data/THIRD_PARTY_LICENSES/hashbrown-0.16.1/LICENSE-APACHE +201 -0
  172. data/THIRD_PARTY_LICENSES/hashbrown-0.16.1/LICENSE-MIT +25 -0
  173. data/THIRD_PARTY_LICENSES/hashbrown-0.17.1/LICENSE-APACHE +201 -0
  174. data/THIRD_PARTY_LICENSES/hashbrown-0.17.1/LICENSE-MIT +25 -0
  175. data/THIRD_PARTY_LICENSES/heck-0.5.0/LICENSE-APACHE +201 -0
  176. data/THIRD_PARTY_LICENSES/heck-0.5.0/LICENSE-MIT +25 -0
  177. data/THIRD_PARTY_LICENSES/hermit-abi-0.5.2/LICENSE-APACHE +201 -0
  178. data/THIRD_PARTY_LICENSES/hermit-abi-0.5.2/LICENSE-MIT +23 -0
  179. data/THIRD_PARTY_LICENSES/hstr-3.0.3/LICENSE +202 -0
  180. data/THIRD_PARTY_LICENSES/html5ever-0.39.0/LICENSE-APACHE +201 -0
  181. data/THIRD_PARTY_LICENSES/html5ever-0.39.0/LICENSE-MIT +25 -0
  182. data/THIRD_PARTY_LICENSES/http-1.5.0/LICENSE-APACHE +201 -0
  183. data/THIRD_PARTY_LICENSES/http-1.5.0/LICENSE-MIT +25 -0
  184. data/THIRD_PARTY_LICENSES/http-body-1.1.0/LICENSE +25 -0
  185. data/THIRD_PARTY_LICENSES/http-body-util-0.1.5/LICENSE +25 -0
  186. data/THIRD_PARTY_LICENSES/http2-0.5.20/LICENSE +25 -0
  187. data/THIRD_PARTY_LICENSES/httparse-1.10.1/LICENSE-APACHE +201 -0
  188. data/THIRD_PARTY_LICENSES/httparse-1.10.1/LICENSE-MIT +20 -0
  189. data/THIRD_PARTY_LICENSES/iana-time-zone-0.1.64/LICENSE-APACHE +201 -0
  190. data/THIRD_PARTY_LICENSES/iana-time-zone-0.1.64/LICENSE-MIT +25 -0
  191. data/THIRD_PARTY_LICENSES/iana-time-zone-haiku-0.1.2/LICENSE-APACHE +201 -0
  192. data/THIRD_PARTY_LICENSES/iana-time-zone-haiku-0.1.2/LICENSE-MIT +25 -0
  193. data/THIRD_PARTY_LICENSES/icu_collections-2.1.1/LICENSE +46 -0
  194. data/THIRD_PARTY_LICENSES/icu_locale_core-2.3.0/LICENSE +46 -0
  195. data/THIRD_PARTY_LICENSES/icu_normalizer-2.1.1/LICENSE +46 -0
  196. data/THIRD_PARTY_LICENSES/icu_normalizer_data-2.1.1/LICENSE +46 -0
  197. data/THIRD_PARTY_LICENSES/icu_properties-2.1.2/LICENSE +46 -0
  198. data/THIRD_PARTY_LICENSES/icu_properties_data-2.1.2/LICENSE +46 -0
  199. data/THIRD_PARTY_LICENSES/icu_provider-2.3.1/LICENSE +46 -0
  200. data/THIRD_PARTY_LICENSES/ident_case-1.0.1/LICENSE +19 -0
  201. data/THIRD_PARTY_LICENSES/idna-1.1.0/LICENSE-APACHE +201 -0
  202. data/THIRD_PARTY_LICENSES/idna-1.1.0/LICENSE-MIT +25 -0
  203. data/THIRD_PARTY_LICENSES/idna_adapter-1.2.1/LICENSE-APACHE +201 -0
  204. data/THIRD_PARTY_LICENSES/idna_adapter-1.2.1/LICENSE-MIT +25 -0
  205. data/THIRD_PARTY_LICENSES/if_chain-1.0.3/LICENSE-APACHE +201 -0
  206. data/THIRD_PARTY_LICENSES/if_chain-1.0.3/LICENSE-MIT +25 -0
  207. data/THIRD_PARTY_LICENSES/indexmap-2.14.2/LICENSE-APACHE +201 -0
  208. data/THIRD_PARTY_LICENSES/indexmap-2.14.2/LICENSE-MIT +25 -0
  209. data/THIRD_PARTY_LICENSES/ipnet-2.12.2/LICENSE-APACHE +201 -0
  210. data/THIRD_PARTY_LICENSES/ipnet-2.12.2/LICENSE-MIT +7 -0
  211. data/THIRD_PARTY_LICENSES/is-macro-0.3.7/LICENSE +202 -0
  212. data/THIRD_PARTY_LICENSES/itertools-0.13.0/LICENSE-APACHE +201 -0
  213. data/THIRD_PARTY_LICENSES/itertools-0.13.0/LICENSE-MIT +25 -0
  214. data/THIRD_PARTY_LICENSES/itoa-1.0.17/LICENSE-APACHE +176 -0
  215. data/THIRD_PARTY_LICENSES/itoa-1.0.17/LICENSE-MIT +23 -0
  216. data/THIRD_PARTY_LICENSES/jobserver-0.1.35/LICENSE-APACHE +201 -0
  217. data/THIRD_PARTY_LICENSES/jobserver-0.1.35/LICENSE-MIT +25 -0
  218. data/THIRD_PARTY_LICENSES/js-sys-0.3.83/LICENSE-APACHE +201 -0
  219. data/THIRD_PARTY_LICENSES/js-sys-0.3.83/LICENSE-MIT +25 -0
  220. data/THIRD_PARTY_LICENSES/jsonc-parser-0.26.3/LICENSE +21 -0
  221. data/THIRD_PARTY_LICENSES/lazy_static-1.5.0/LICENSE-APACHE +201 -0
  222. data/THIRD_PARTY_LICENSES/lazy_static-1.5.0/LICENSE-MIT +25 -0
  223. data/THIRD_PARTY_LICENSES/libc-0.2.189/LICENSE-APACHE +176 -0
  224. data/THIRD_PARTY_LICENSES/libc-0.2.189/LICENSE-MIT +25 -0
  225. data/THIRD_PARTY_LICENSES/libloading-0.8.9/LICENSE +12 -0
  226. data/THIRD_PARTY_LICENSES/litemap-0.8.1/LICENSE +46 -0
  227. data/THIRD_PARTY_LICENSES/lock_api-0.4.14/LICENSE-APACHE +201 -0
  228. data/THIRD_PARTY_LICENSES/lock_api-0.4.14/LICENSE-MIT +25 -0
  229. data/THIRD_PARTY_LICENSES/log-0.4.34/LICENSE-APACHE +201 -0
  230. data/THIRD_PARTY_LICENSES/log-0.4.34/LICENSE-MIT +25 -0
  231. data/THIRD_PARTY_LICENSES/lru-0.16.2/LICENSE +21 -0
  232. data/THIRD_PARTY_LICENSES/lru-0.18.4/LICENSE +21 -0
  233. data/THIRD_PARTY_LICENSES/markup5ever-0.39.0/LICENSE-APACHE +201 -0
  234. data/THIRD_PARTY_LICENSES/markup5ever-0.39.0/LICENSE-MIT +25 -0
  235. data/THIRD_PARTY_LICENSES/memchr-2.7.6/COPYING +3 -0
  236. data/THIRD_PARTY_LICENSES/memchr-2.7.6/LICENSE-MIT +21 -0
  237. data/THIRD_PARTY_LICENSES/miette-7.6.0/LICENSE +202 -0
  238. data/THIRD_PARTY_LICENSES/miette-derive-7.6.0/LICENSE +229 -0
  239. data/THIRD_PARTY_LICENSES/minimal-lexical-0.2.1/LICENSE-APACHE +201 -0
  240. data/THIRD_PARTY_LICENSES/minimal-lexical-0.2.1/LICENSE-MIT +23 -0
  241. data/THIRD_PARTY_LICENSES/minimal-lexical-0.2.1/LICENSE.md +37 -0
  242. data/THIRD_PARTY_LICENSES/miniz_oxide-0.9.1/LICENSE +25 -0
  243. data/THIRD_PARTY_LICENSES/miniz_oxide-0.9.1/LICENSE-APACHE.md +177 -0
  244. data/THIRD_PARTY_LICENSES/miniz_oxide-0.9.1/LICENSE-MIT.md +24 -0
  245. data/THIRD_PARTY_LICENSES/miniz_oxide-0.9.1/LICENSE-ZLIB.md +14 -0
  246. data/THIRD_PARTY_LICENSES/mio-1.2.3/LICENSE +19 -0
  247. data/THIRD_PARTY_LICENSES/new_debug_unreachable-1.0.6/LICENSE-MIT +25 -0
  248. data/THIRD_PARTY_LICENSES/nom-7.1.3/LICENSE +20 -0
  249. data/THIRD_PARTY_LICENSES/normpath-0.2.0/COPYRIGHT +7 -0
  250. data/THIRD_PARTY_LICENSES/normpath-0.2.0/LICENSE-APACHE +201 -0
  251. data/THIRD_PARTY_LICENSES/normpath-0.2.0/LICENSE-MIT +21 -0
  252. data/THIRD_PARTY_LICENSES/normpath-0.2.0/LICENSE-THIRD-PARTY +210 -0
  253. data/THIRD_PARTY_LICENSES/num-bigint-0.4.6/LICENSE-APACHE +201 -0
  254. data/THIRD_PARTY_LICENSES/num-bigint-0.4.6/LICENSE-MIT +25 -0
  255. data/THIRD_PARTY_LICENSES/num-conv-0.2.2/LICENSE-Apache +177 -0
  256. data/THIRD_PARTY_LICENSES/num-conv-0.2.2/LICENSE-MIT +19 -0
  257. data/THIRD_PARTY_LICENSES/num-integer-0.1.46/LICENSE-APACHE +201 -0
  258. data/THIRD_PARTY_LICENSES/num-integer-0.1.46/LICENSE-MIT +25 -0
  259. data/THIRD_PARTY_LICENSES/num-traits-0.2.19/LICENSE-APACHE +201 -0
  260. data/THIRD_PARTY_LICENSES/num-traits-0.2.19/LICENSE-MIT +25 -0
  261. data/THIRD_PARTY_LICENSES/num_cpus-1.17.0/LICENSE-APACHE +201 -0
  262. data/THIRD_PARTY_LICENSES/num_cpus-1.17.0/LICENSE-MIT +20 -0
  263. data/THIRD_PARTY_LICENSES/once_cell-1.21.3/LICENSE-APACHE +201 -0
  264. data/THIRD_PARTY_LICENSES/once_cell-1.21.3/LICENSE-MIT +23 -0
  265. data/THIRD_PARTY_LICENSES/openssl-macros-0.1.1/LICENSE-APACHE +202 -0
  266. data/THIRD_PARTY_LICENSES/openssl-macros-0.1.1/LICENSE-MIT +19 -0
  267. data/THIRD_PARTY_LICENSES/outref-0.5.2/LICENSE +21 -0
  268. data/THIRD_PARTY_LICENSES/owo-colors-4.2.3/LICENSE +21 -0
  269. data/THIRD_PARTY_LICENSES/par-core-2.0.0/LICENSE +202 -0
  270. data/THIRD_PARTY_LICENSES/par-iter-2.0.0/LICENSE +202 -0
  271. data/THIRD_PARTY_LICENSES/parking_lot-0.12.5/LICENSE-APACHE +201 -0
  272. data/THIRD_PARTY_LICENSES/parking_lot-0.12.5/LICENSE-MIT +25 -0
  273. data/THIRD_PARTY_LICENSES/parking_lot_core-0.9.12/LICENSE-APACHE +201 -0
  274. data/THIRD_PARTY_LICENSES/parking_lot_core-0.9.12/LICENSE-MIT +25 -0
  275. data/THIRD_PARTY_LICENSES/path-clean-0.1.0/LICENSE-APACHE +13 -0
  276. data/THIRD_PARTY_LICENSES/path-clean-0.1.0/LICENSE-MIT +18 -0
  277. data/THIRD_PARTY_LICENSES/path-clean-1.0.1/LICENSE-APACHE +13 -0
  278. data/THIRD_PARTY_LICENSES/path-clean-1.0.1/LICENSE-MIT +18 -0
  279. data/THIRD_PARTY_LICENSES/pathdiff-0.2.3/LICENSE-APACHE +201 -0
  280. data/THIRD_PARTY_LICENSES/pathdiff-0.2.3/LICENSE-MIT +23 -0
  281. data/THIRD_PARTY_LICENSES/percent-encoding-2.3.2/LICENSE-APACHE +201 -0
  282. data/THIRD_PARTY_LICENSES/percent-encoding-2.3.2/LICENSE-MIT +25 -0
  283. data/THIRD_PARTY_LICENSES/petgraph-0.7.1/LICENSE-APACHE +201 -0
  284. data/THIRD_PARTY_LICENSES/petgraph-0.7.1/LICENSE-MIT +25 -0
  285. data/THIRD_PARTY_LICENSES/phf-0.11.3/LICENSE +20 -0
  286. data/THIRD_PARTY_LICENSES/phf-0.13.1/LICENSE +20 -0
  287. data/THIRD_PARTY_LICENSES/phf_codegen-0.13.1/LICENSE +20 -0
  288. data/THIRD_PARTY_LICENSES/phf_generator-0.11.3/LICENSE +20 -0
  289. data/THIRD_PARTY_LICENSES/phf_generator-0.13.1/LICENSE +20 -0
  290. data/THIRD_PARTY_LICENSES/phf_macros-0.11.3/LICENSE +20 -0
  291. data/THIRD_PARTY_LICENSES/phf_macros-0.13.1/LICENSE +20 -0
  292. data/THIRD_PARTY_LICENSES/phf_shared-0.11.3/LICENSE +20 -0
  293. data/THIRD_PARTY_LICENSES/phf_shared-0.13.1/LICENSE +20 -0
  294. data/THIRD_PARTY_LICENSES/pin-project-lite-0.2.17/LICENSE-APACHE +177 -0
  295. data/THIRD_PARTY_LICENSES/pin-project-lite-0.2.17/LICENSE-MIT +23 -0
  296. data/THIRD_PARTY_LICENSES/pkg-config-0.3.34/LICENSE-APACHE +201 -0
  297. data/THIRD_PARTY_LICENSES/pkg-config-0.3.34/LICENSE-MIT +25 -0
  298. data/THIRD_PARTY_LICENSES/potential_utf-0.1.4/LICENSE +46 -0
  299. data/THIRD_PARTY_LICENSES/powerfmt-0.2.0/LICENSE-Apache +202 -0
  300. data/THIRD_PARTY_LICENSES/powerfmt-0.2.0/LICENSE-MIT +19 -0
  301. data/THIRD_PARTY_LICENSES/ppv-lite86-0.2.21/LICENSE-APACHE +201 -0
  302. data/THIRD_PARTY_LICENSES/ppv-lite86-0.2.21/LICENSE-MIT +25 -0
  303. data/THIRD_PARTY_LICENSES/precomputed-hash-0.1.1/LICENSE +21 -0
  304. data/THIRD_PARTY_LICENSES/precomputed-map-0.2.0/LICENSE +21 -0
  305. data/THIRD_PARTY_LICENSES/preset_env_base-6.0.0/LICENSE +201 -0
  306. data/THIRD_PARTY_LICENSES/proc-macro2-1.0.107/LICENSE-APACHE +176 -0
  307. data/THIRD_PARTY_LICENSES/proc-macro2-1.0.107/LICENSE-MIT +23 -0
  308. data/THIRD_PARTY_LICENSES/quote-1.0.47/LICENSE-APACHE +176 -0
  309. data/THIRD_PARTY_LICENSES/quote-1.0.47/LICENSE-MIT +23 -0
  310. data/THIRD_PARTY_LICENSES/r-efi-5.3.0/LICENSE-APACHE +176 -0
  311. data/THIRD_PARTY_LICENSES/r-efi-6.0.0/LICENSE-APACHE +176 -0
  312. data/THIRD_PARTY_LICENSES/radium-0.7.0/LICENSE.txt +21 -0
  313. data/THIRD_PARTY_LICENSES/radix_fmt-1.0.0/LICENSE +201 -0
  314. data/THIRD_PARTY_LICENSES/rand-0.8.5/COPYRIGHT +12 -0
  315. data/THIRD_PARTY_LICENSES/rand-0.8.5/LICENSE-APACHE +176 -0
  316. data/THIRD_PARTY_LICENSES/rand-0.8.5/LICENSE-MIT +26 -0
  317. data/THIRD_PARTY_LICENSES/rand-0.9.5/COPYRIGHT +12 -0
  318. data/THIRD_PARTY_LICENSES/rand-0.9.5/LICENSE-APACHE +176 -0
  319. data/THIRD_PARTY_LICENSES/rand-0.9.5/LICENSE-MIT +26 -0
  320. data/THIRD_PARTY_LICENSES/rand_chacha-0.9.0/COPYRIGHT +12 -0
  321. data/THIRD_PARTY_LICENSES/rand_chacha-0.9.0/LICENSE-APACHE +176 -0
  322. data/THIRD_PARTY_LICENSES/rand_chacha-0.9.0/LICENSE-MIT +26 -0
  323. data/THIRD_PARTY_LICENSES/rand_core-0.6.4/COPYRIGHT +12 -0
  324. data/THIRD_PARTY_LICENSES/rand_core-0.6.4/LICENSE-APACHE +187 -0
  325. data/THIRD_PARTY_LICENSES/rand_core-0.6.4/LICENSE-MIT +26 -0
  326. data/THIRD_PARTY_LICENSES/rand_core-0.9.5/COPYRIGHT +12 -0
  327. data/THIRD_PARTY_LICENSES/rand_core-0.9.5/LICENSE-APACHE +187 -0
  328. data/THIRD_PARTY_LICENSES/rand_core-0.9.5/LICENSE-MIT +26 -0
  329. data/THIRD_PARTY_LICENSES/redox_syscall-0.5.18/LICENSE +22 -0
  330. data/THIRD_PARTY_LICENSES/regex-1.12.2/LICENSE-APACHE +201 -0
  331. data/THIRD_PARTY_LICENSES/regex-1.12.2/LICENSE-MIT +25 -0
  332. data/THIRD_PARTY_LICENSES/regex-automata-0.4.13/LICENSE-APACHE +201 -0
  333. data/THIRD_PARTY_LICENSES/regex-automata-0.4.13/LICENSE-MIT +25 -0
  334. data/THIRD_PARTY_LICENSES/regex-syntax-0.8.8/LICENSE-APACHE +201 -0
  335. data/THIRD_PARTY_LICENSES/regex-syntax-0.8.8/LICENSE-MIT +25 -0
  336. data/THIRD_PARTY_LICENSES/regress-0.10.5/LICENSE-APACHE +201 -0
  337. data/THIRD_PARTY_LICENSES/regress-0.10.5/LICENSE-MIT +21 -0
  338. data/THIRD_PARTY_LICENSES/rustc-hash-2.1.1/LICENSE-APACHE +176 -0
  339. data/THIRD_PARTY_LICENSES/rustc-hash-2.1.1/LICENSE-MIT +23 -0
  340. data/THIRD_PARTY_LICENSES/rustc_version-0.4.1/LICENSE-APACHE +201 -0
  341. data/THIRD_PARTY_LICENSES/rustc_version-0.4.1/LICENSE-MIT +25 -0
  342. data/THIRD_PARTY_LICENSES/rustls-pki-types-1.15.1/LICENSE-APACHE +201 -0
  343. data/THIRD_PARTY_LICENSES/rustls-pki-types-1.15.1/LICENSE-MIT +25 -0
  344. data/THIRD_PARTY_LICENSES/rustversion-1.0.22/LICENSE-APACHE +176 -0
  345. data/THIRD_PARTY_LICENSES/rustversion-1.0.22/LICENSE-MIT +23 -0
  346. data/THIRD_PARTY_LICENSES/ryu-1.0.22/LICENSE-APACHE +176 -0
  347. data/THIRD_PARTY_LICENSES/ryu-1.0.22/LICENSE-BOOST +23 -0
  348. data/THIRD_PARTY_LICENSES/ryu-js-1.0.2/LICENSE-APACHE +176 -0
  349. data/THIRD_PARTY_LICENSES/ryu-js-1.0.2/LICENSE-BOOST +23 -0
  350. data/THIRD_PARTY_LICENSES/scoped-tls-1.0.1/LICENSE-APACHE +201 -0
  351. data/THIRD_PARTY_LICENSES/scoped-tls-1.0.1/LICENSE-MIT +25 -0
  352. data/THIRD_PARTY_LICENSES/scopeguard-1.2.0/LICENSE-APACHE +201 -0
  353. data/THIRD_PARTY_LICENSES/scopeguard-1.2.0/LICENSE-MIT +25 -0
  354. data/THIRD_PARTY_LICENSES/scraper-0.27.0/LICENSE +15 -0
  355. data/THIRD_PARTY_LICENSES/selectors-0.38.0/LICENSE +373 -0
  356. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/CHANGES.md +1 -0
  357. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/Cargo.lock +513 -0
  358. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/Cargo.toml +88 -0
  359. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/Cargo.toml.orig +37 -0
  360. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/README.md +24 -0
  361. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/attr.rs +196 -0
  362. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/bloom.rs +422 -0
  363. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/build.rs +77 -0
  364. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/builder.rs +455 -0
  365. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/context.rs +525 -0
  366. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/kleene_value.rs +131 -0
  367. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/lib.rs +23 -0
  368. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/matching.rs +1609 -0
  369. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/nth_index_cache.rs +102 -0
  370. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/parser.rs +4857 -0
  371. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/relative_selector/cache.rs +81 -0
  372. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/relative_selector/filter.rs +159 -0
  373. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/relative_selector/mod.rs +6 -0
  374. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/sink.rs +31 -0
  375. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/tree.rs +184 -0
  376. data/THIRD_PARTY_LICENSES/selectors-0.38.0/source/visitor.rs +137 -0
  377. data/THIRD_PARTY_LICENSES/semver-1.0.27/LICENSE-APACHE +176 -0
  378. data/THIRD_PARTY_LICENSES/semver-1.0.27/LICENSE-MIT +23 -0
  379. data/THIRD_PARTY_LICENSES/seq-macro-0.3.6/LICENSE-APACHE +176 -0
  380. data/THIRD_PARTY_LICENSES/seq-macro-0.3.6/LICENSE-MIT +23 -0
  381. data/THIRD_PARTY_LICENSES/serde-1.0.228/LICENSE-APACHE +176 -0
  382. data/THIRD_PARTY_LICENSES/serde-1.0.228/LICENSE-MIT +23 -0
  383. data/THIRD_PARTY_LICENSES/serde_core-1.0.228/LICENSE-APACHE +176 -0
  384. data/THIRD_PARTY_LICENSES/serde_core-1.0.228/LICENSE-MIT +23 -0
  385. data/THIRD_PARTY_LICENSES/serde_derive-1.0.228/LICENSE-APACHE +176 -0
  386. data/THIRD_PARTY_LICENSES/serde_derive-1.0.228/LICENSE-MIT +23 -0
  387. data/THIRD_PARTY_LICENSES/serde_json-1.0.151/LICENSE-APACHE +176 -0
  388. data/THIRD_PARTY_LICENSES/serde_json-1.0.151/LICENSE-MIT +23 -0
  389. data/THIRD_PARTY_LICENSES/servo_arc-0.4.3/LICENSE-APACHE +201 -0
  390. data/THIRD_PARTY_LICENSES/servo_arc-0.4.3/LICENSE-MIT +23 -0
  391. data/THIRD_PARTY_LICENSES/sha1-0.10.6/LICENSE-APACHE +201 -0
  392. data/THIRD_PARTY_LICENSES/sha1-0.10.6/LICENSE-MIT +27 -0
  393. data/THIRD_PARTY_LICENSES/sha2-0.10.9/LICENSE-APACHE +201 -0
  394. data/THIRD_PARTY_LICENSES/sha2-0.10.9/LICENSE-MIT +27 -0
  395. data/THIRD_PARTY_LICENSES/shlex-1.3.0/LICENSE-APACHE +13 -0
  396. data/THIRD_PARTY_LICENSES/shlex-1.3.0/LICENSE-MIT +21 -0
  397. data/THIRD_PARTY_LICENSES/signal-hook-registry-1.4.8/LICENSE-APACHE +201 -0
  398. data/THIRD_PARTY_LICENSES/signal-hook-registry-1.4.8/LICENSE-MIT +25 -0
  399. data/THIRD_PARTY_LICENSES/simd-adler32-0.3.10/LICENSE.md +21 -0
  400. data/THIRD_PARTY_LICENSES/siphasher-0.3.11/COPYING +7 -0
  401. data/THIRD_PARTY_LICENSES/siphasher-1.0.1/COPYING +7 -0
  402. data/THIRD_PARTY_LICENSES/slab-0.4.12/LICENSE +25 -0
  403. data/THIRD_PARTY_LICENSES/smallvec-1.15.1/LICENSE-APACHE +201 -0
  404. data/THIRD_PARTY_LICENSES/smallvec-1.15.1/LICENSE-MIT +25 -0
  405. data/THIRD_PARTY_LICENSES/smartstring-1.0.1/LICENCE.md +355 -0
  406. data/THIRD_PARTY_LICENSES/socket2-0.6.5/LICENSE-APACHE +201 -0
  407. data/THIRD_PARTY_LICENSES/socket2-0.6.5/LICENSE-MIT +25 -0
  408. data/THIRD_PARTY_LICENSES/st-map-0.2.4/LICENSE +202 -0
  409. data/THIRD_PARTY_LICENSES/stable_deref_trait-1.2.1/LICENSE-APACHE +201 -0
  410. data/THIRD_PARTY_LICENSES/stable_deref_trait-1.2.1/LICENSE-MIT +25 -0
  411. data/THIRD_PARTY_LICENSES/static-map-macro-0.3.4/LICENSE +202 -0
  412. data/THIRD_PARTY_LICENSES/static_assertions-1.1.0/LICENSE-APACHE +202 -0
  413. data/THIRD_PARTY_LICENSES/static_assertions-1.1.0/LICENSE-MIT +21 -0
  414. data/THIRD_PARTY_LICENSES/string_cache-0.9.0/LICENSE-APACHE +201 -0
  415. data/THIRD_PARTY_LICENSES/string_cache-0.9.0/LICENSE-MIT +25 -0
  416. data/THIRD_PARTY_LICENSES/string_cache_codegen-0.6.1/LICENSE-APACHE +201 -0
  417. data/THIRD_PARTY_LICENSES/string_cache_codegen-0.6.1/LICENSE-MIT +25 -0
  418. data/THIRD_PARTY_LICENSES/string_enum-1.0.2/LICENSE +201 -0
  419. data/THIRD_PARTY_LICENSES/strsim-0.11.1/LICENSE +23 -0
  420. data/THIRD_PARTY_LICENSES/swc-52.0.0/LICENSE +201 -0
  421. data/THIRD_PARTY_LICENSES/swc_allocator-4.0.1/LICENSE +201 -0
  422. data/THIRD_PARTY_LICENSES/swc_atoms-9.0.0/LICENSE +201 -0
  423. data/THIRD_PARTY_LICENSES/swc_common-18.0.1/LICENSE +201 -0
  424. data/THIRD_PARTY_LICENSES/swc_compiler_base-45.0.0/LICENSE +201 -0
  425. data/THIRD_PARTY_LICENSES/swc_config-3.1.2/LICENSE +201 -0
  426. data/THIRD_PARTY_LICENSES/swc_config_macro-1.0.1/LICENSE +201 -0
  427. data/THIRD_PARTY_LICENSES/swc_core-54.0.0/LICENSE +201 -0
  428. data/THIRD_PARTY_LICENSES/swc_ecma_ast-19.0.0/LICENSE +201 -0
  429. data/THIRD_PARTY_LICENSES/swc_ecma_codegen-21.0.0/LICENSE +201 -0
  430. data/THIRD_PARTY_LICENSES/swc_ecma_codegen_macros-2.0.2/LICENSE +201 -0
  431. data/THIRD_PARTY_LICENSES/swc_ecma_compat_bugfixes-39.0.0/LICENSE +201 -0
  432. data/THIRD_PARTY_LICENSES/swc_ecma_compat_common-30.0.0/LICENSE +201 -0
  433. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2015-39.0.0/LICENSE +201 -0
  434. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2016-35.0.0/LICENSE +201 -0
  435. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2017-35.0.0/LICENSE +201 -0
  436. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2018-36.0.0/LICENSE +201 -0
  437. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2019-35.0.0/LICENSE +201 -0
  438. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2020-37.0.0/LICENSE +201 -0
  439. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2021-35.0.0/LICENSE +201 -0
  440. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es2022-37.0.0/LICENSE +201 -0
  441. data/THIRD_PARTY_LICENSES/swc_ecma_compat_es3-26.0.0/LICENSE +201 -0
  442. data/THIRD_PARTY_LICENSES/swc_ecma_ext_transforms-25.0.0/LICENSE +201 -0
  443. data/THIRD_PARTY_LICENSES/swc_ecma_hooks-0.3.0/LICENSE +201 -0
  444. data/THIRD_PARTY_LICENSES/swc_ecma_loader-18.0.0/LICENSE +201 -0
  445. data/THIRD_PARTY_LICENSES/swc_ecma_minifier-42.0.0/LICENSE +201 -0
  446. data/THIRD_PARTY_LICENSES/swc_ecma_parser-32.0.0/LICENSE +201 -0
  447. data/THIRD_PARTY_LICENSES/swc_ecma_preset_env-45.0.0/LICENSE +201 -0
  448. data/THIRD_PARTY_LICENSES/swc_ecma_transformer-6.0.0/LICENSE +201 -0
  449. data/THIRD_PARTY_LICENSES/swc_ecma_transforms-44.0.0/LICENSE +201 -0
  450. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_base-35.0.0/LICENSE +201 -0
  451. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_classes-35.0.0/LICENSE +201 -0
  452. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_compat-40.0.0/LICENSE +201 -0
  453. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_macros-1.0.1/LICENSE +201 -0
  454. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_module-38.0.0/LICENSE +201 -0
  455. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_optimization-37.0.0/LICENSE +201 -0
  456. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_proposal-35.0.0/LICENSE +201 -0
  457. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_react-38.0.0/LICENSE +201 -0
  458. data/THIRD_PARTY_LICENSES/swc_ecma_transforms_typescript-38.0.0/LICENSE +201 -0
  459. data/THIRD_PARTY_LICENSES/swc_ecma_usage_analyzer-27.0.0/LICENSE +201 -0
  460. data/THIRD_PARTY_LICENSES/swc_ecma_utils-25.0.0/LICENSE +201 -0
  461. data/THIRD_PARTY_LICENSES/swc_ecma_visit-19.0.0/LICENSE +201 -0
  462. data/THIRD_PARTY_LICENSES/swc_eq_ignore_macros-1.0.1/LICENSE +201 -0
  463. data/THIRD_PARTY_LICENSES/swc_error_reporters-20.0.0/LICENSE +201 -0
  464. data/THIRD_PARTY_LICENSES/swc_macros_common-1.0.1/LICENSE +201 -0
  465. data/THIRD_PARTY_LICENSES/swc_node_comments-18.0.0/LICENSE +201 -0
  466. data/THIRD_PARTY_LICENSES/swc_sourcemap-9.3.4/LICENSE +31 -0
  467. data/THIRD_PARTY_LICENSES/swc_timer-1.0.0/LICENSE +201 -0
  468. data/THIRD_PARTY_LICENSES/swc_trace_macro-2.0.2/LICENSE +201 -0
  469. data/THIRD_PARTY_LICENSES/swc_transform_common-12.0.0/LICENSE +201 -0
  470. data/THIRD_PARTY_LICENSES/swc_visit-2.0.1/LICENSE +201 -0
  471. data/THIRD_PARTY_LICENSES/syn-2.0.113/LICENSE-APACHE +176 -0
  472. data/THIRD_PARTY_LICENSES/syn-2.0.113/LICENSE-MIT +23 -0
  473. data/THIRD_PARTY_LICENSES/syn-3.0.5/LICENSE-APACHE +176 -0
  474. data/THIRD_PARTY_LICENSES/syn-3.0.5/LICENSE-MIT +23 -0
  475. data/THIRD_PARTY_LICENSES/sync_wrapper-1.0.2/LICENSE +177 -0
  476. data/THIRD_PARTY_LICENSES/synstructure-0.13.2/LICENSE +7 -0
  477. data/THIRD_PARTY_LICENSES/synstructure-0.14.0/LICENSE +7 -0
  478. data/THIRD_PARTY_LICENSES/tap-1.0.1/LICENSE.txt +21 -0
  479. data/THIRD_PARTY_LICENSES/tendril-0.5.1/LICENSE-APACHE +201 -0
  480. data/THIRD_PARTY_LICENSES/tendril-0.5.1/LICENSE-MIT +25 -0
  481. data/THIRD_PARTY_LICENSES/textwrap-0.16.2/LICENSE +21 -0
  482. data/THIRD_PARTY_LICENSES/thiserror-1.0.69/LICENSE-APACHE +176 -0
  483. data/THIRD_PARTY_LICENSES/thiserror-1.0.69/LICENSE-MIT +23 -0
  484. data/THIRD_PARTY_LICENSES/thiserror-2.0.21/LICENSE-APACHE +176 -0
  485. data/THIRD_PARTY_LICENSES/thiserror-2.0.21/LICENSE-MIT +23 -0
  486. data/THIRD_PARTY_LICENSES/thiserror-impl-1.0.69/LICENSE-APACHE +176 -0
  487. data/THIRD_PARTY_LICENSES/thiserror-impl-1.0.69/LICENSE-MIT +23 -0
  488. data/THIRD_PARTY_LICENSES/thiserror-impl-2.0.21/LICENSE-APACHE +176 -0
  489. data/THIRD_PARTY_LICENSES/thiserror-impl-2.0.21/LICENSE-MIT +23 -0
  490. data/THIRD_PARTY_LICENSES/time-0.3.55/LICENSE-Apache +177 -0
  491. data/THIRD_PARTY_LICENSES/time-0.3.55/LICENSE-MIT +19 -0
  492. data/THIRD_PARTY_LICENSES/time-core-0.1.9/LICENSE-Apache +177 -0
  493. data/THIRD_PARTY_LICENSES/time-core-0.1.9/LICENSE-MIT +19 -0
  494. data/THIRD_PARTY_LICENSES/time-macros-0.2.32/LICENSE-Apache +177 -0
  495. data/THIRD_PARTY_LICENSES/time-macros-0.2.32/LICENSE-MIT +19 -0
  496. data/THIRD_PARTY_LICENSES/tinystr-0.8.4/LICENSE +46 -0
  497. data/THIRD_PARTY_LICENSES/tokio-1.53.1/LICENSE +21 -0
  498. data/THIRD_PARTY_LICENSES/tokio-btls-0.5.6/LICENSE-APACHE +202 -0
  499. data/THIRD_PARTY_LICENSES/tokio-btls-0.5.6/LICENSE-MIT +27 -0
  500. data/THIRD_PARTY_LICENSES/tokio-macros-2.7.2/LICENSE +22 -0
  501. data/THIRD_PARTY_LICENSES/tokio-socks-0.5.3/LICENSE +21 -0
  502. data/THIRD_PARTY_LICENSES/tokio-tungstenite-0.29.0/LICENSE +20 -0
  503. data/THIRD_PARTY_LICENSES/tokio-util-0.7.19/LICENSE +21 -0
  504. data/THIRD_PARTY_LICENSES/tower-0.5.3/LICENSE +25 -0
  505. data/THIRD_PARTY_LICENSES/tower-http-0.6.11/LICENSE +25 -0
  506. data/THIRD_PARTY_LICENSES/tower-layer-0.3.3/LICENSE +25 -0
  507. data/THIRD_PARTY_LICENSES/tower-service-0.3.3/LICENSE +25 -0
  508. data/THIRD_PARTY_LICENSES/tracing-0.1.44/LICENSE +25 -0
  509. data/THIRD_PARTY_LICENSES/tracing-attributes-0.1.31/LICENSE +25 -0
  510. data/THIRD_PARTY_LICENSES/tracing-core-0.1.36/LICENSE +25 -0
  511. data/THIRD_PARTY_LICENSES/triomphe-0.1.15/LICENSE-APACHE +201 -0
  512. data/THIRD_PARTY_LICENSES/triomphe-0.1.15/LICENSE-MIT +27 -0
  513. data/THIRD_PARTY_LICENSES/try-lock-0.2.5/LICENSE +21 -0
  514. data/THIRD_PARTY_LICENSES/tungstenite-0.29.0/LICENSE-APACHE +201 -0
  515. data/THIRD_PARTY_LICENSES/tungstenite-0.29.0/LICENSE-MIT +20 -0
  516. data/THIRD_PARTY_LICENSES/typed-builder-0.23.2/LICENSE-APACHE +201 -0
  517. data/THIRD_PARTY_LICENSES/typed-builder-0.23.2/LICENSE-MIT +23 -0
  518. data/THIRD_PARTY_LICENSES/typed-builder-macro-0.23.2/LICENSE-APACHE +201 -0
  519. data/THIRD_PARTY_LICENSES/typed-builder-macro-0.23.2/LICENSE-MIT +23 -0
  520. data/THIRD_PARTY_LICENSES/typenum-1.19.0/LICENSE +1 -0
  521. data/THIRD_PARTY_LICENSES/typenum-1.19.0/LICENSE-APACHE +201 -0
  522. data/THIRD_PARTY_LICENSES/typenum-1.19.0/LICENSE-MIT +21 -0
  523. data/THIRD_PARTY_LICENSES/unicode-id-start-1.4.0/LICENSE-APACHE +176 -0
  524. data/THIRD_PARTY_LICENSES/unicode-id-start-1.4.0/LICENSE-MIT +23 -0
  525. data/THIRD_PARTY_LICENSES/unicode-id-start-1.4.0/LICENSE-UNICODE +39 -0
  526. data/THIRD_PARTY_LICENSES/unicode-ident-1.0.22/LICENSE-APACHE +176 -0
  527. data/THIRD_PARTY_LICENSES/unicode-ident-1.0.22/LICENSE-MIT +23 -0
  528. data/THIRD_PARTY_LICENSES/unicode-ident-1.0.22/LICENSE-UNICODE +39 -0
  529. data/THIRD_PARTY_LICENSES/unicode-linebreak-0.1.5/LICENSE +201 -0
  530. data/THIRD_PARTY_LICENSES/unicode-width-0.1.14/COPYRIGHT +7 -0
  531. data/THIRD_PARTY_LICENSES/unicode-width-0.1.14/LICENSE-APACHE +201 -0
  532. data/THIRD_PARTY_LICENSES/unicode-width-0.1.14/LICENSE-MIT +25 -0
  533. data/THIRD_PARTY_LICENSES/unicode-width-0.2.2/COPYRIGHT +7 -0
  534. data/THIRD_PARTY_LICENSES/unicode-width-0.2.2/LICENSE-APACHE +201 -0
  535. data/THIRD_PARTY_LICENSES/unicode-width-0.2.2/LICENSE-MIT +25 -0
  536. data/THIRD_PARTY_LICENSES/url-2.5.8/LICENSE-APACHE +201 -0
  537. data/THIRD_PARTY_LICENSES/url-2.5.8/LICENSE-MIT +25 -0
  538. data/THIRD_PARTY_LICENSES/utf8_iter-1.0.4/COPYRIGHT +42 -0
  539. data/THIRD_PARTY_LICENSES/utf8_iter-1.0.4/LICENSE-APACHE +202 -0
  540. data/THIRD_PARTY_LICENSES/utf8_iter-1.0.4/LICENSE-MIT +25 -0
  541. data/THIRD_PARTY_LICENSES/uuid-1.19.0/LICENSE-APACHE +201 -0
  542. data/THIRD_PARTY_LICENSES/uuid-1.19.0/LICENSE-MIT +26 -0
  543. data/THIRD_PARTY_LICENSES/vergen-9.0.6/LICENSE-APACHE +201 -0
  544. data/THIRD_PARTY_LICENSES/vergen-9.0.6/LICENSE-MIT +25 -0
  545. data/THIRD_PARTY_LICENSES/vergen-lib-0.1.6/LICENSE-APACHE +201 -0
  546. data/THIRD_PARTY_LICENSES/vergen-lib-0.1.6/LICENSE-MIT +25 -0
  547. data/THIRD_PARTY_LICENSES/version_check-0.9.5/LICENSE-APACHE +201 -0
  548. data/THIRD_PARTY_LICENSES/version_check-0.9.5/LICENSE-MIT +19 -0
  549. data/THIRD_PARTY_LICENSES/vsimd-0.8.0/LICENSE +21 -0
  550. data/THIRD_PARTY_LICENSES/want-0.3.1/LICENSE +20 -0
  551. data/THIRD_PARTY_LICENSES/wasi-0.11.1+wasi-snapshot-preview1/LICENSE-APACHE +201 -0
  552. data/THIRD_PARTY_LICENSES/wasi-0.11.1+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  553. data/THIRD_PARTY_LICENSES/wasi-0.11.1+wasi-snapshot-preview1/LICENSE-MIT +23 -0
  554. data/THIRD_PARTY_LICENSES/wasip2-1.0.1+wasi-0.2.4/LICENSE-APACHE +201 -0
  555. data/THIRD_PARTY_LICENSES/wasm-bindgen-0.2.106/LICENSE-APACHE +201 -0
  556. data/THIRD_PARTY_LICENSES/wasm-bindgen-0.2.106/LICENSE-MIT +25 -0
  557. data/THIRD_PARTY_LICENSES/wasm-bindgen-macro-0.2.106/LICENSE-APACHE +201 -0
  558. data/THIRD_PARTY_LICENSES/wasm-bindgen-macro-0.2.106/LICENSE-MIT +25 -0
  559. data/THIRD_PARTY_LICENSES/wasm-bindgen-macro-support-0.2.106/LICENSE-APACHE +201 -0
  560. data/THIRD_PARTY_LICENSES/wasm-bindgen-macro-support-0.2.106/LICENSE-MIT +25 -0
  561. data/THIRD_PARTY_LICENSES/wasm-bindgen-shared-0.2.106/LICENSE-APACHE +201 -0
  562. data/THIRD_PARTY_LICENSES/wasm-bindgen-shared-0.2.106/LICENSE-MIT +25 -0
  563. data/THIRD_PARTY_LICENSES/web_atoms-0.2.6/LICENSE-APACHE +201 -0
  564. data/THIRD_PARTY_LICENSES/web_atoms-0.2.6/LICENSE-MIT +25 -0
  565. data/THIRD_PARTY_LICENSES/webpki-root-certs-1.0.9/LICENSE +61 -0
  566. data/THIRD_PARTY_LICENSES/winapi-0.3.9/LICENSE-APACHE +201 -0
  567. data/THIRD_PARTY_LICENSES/winapi-0.3.9/LICENSE-MIT +19 -0
  568. data/THIRD_PARTY_LICENSES/winapi-i686-pc-windows-gnu-0.4.0/LICENSE-APACHE +201 -0
  569. data/THIRD_PARTY_LICENSES/winapi-x86_64-pc-windows-gnu-0.4.0/LICENSE-APACHE +201 -0
  570. data/THIRD_PARTY_LICENSES/windows-core-0.62.2/license-apache-2.0 +201 -0
  571. data/THIRD_PARTY_LICENSES/windows-core-0.62.2/license-mit +21 -0
  572. data/THIRD_PARTY_LICENSES/windows-implement-0.60.2/license-apache-2.0 +201 -0
  573. data/THIRD_PARTY_LICENSES/windows-implement-0.60.2/license-mit +21 -0
  574. data/THIRD_PARTY_LICENSES/windows-interface-0.59.3/license-apache-2.0 +201 -0
  575. data/THIRD_PARTY_LICENSES/windows-interface-0.59.3/license-mit +21 -0
  576. data/THIRD_PARTY_LICENSES/windows-link-0.2.1/license-apache-2.0 +201 -0
  577. data/THIRD_PARTY_LICENSES/windows-link-0.2.1/license-mit +21 -0
  578. data/THIRD_PARTY_LICENSES/windows-result-0.4.1/license-apache-2.0 +201 -0
  579. data/THIRD_PARTY_LICENSES/windows-result-0.4.1/license-mit +21 -0
  580. data/THIRD_PARTY_LICENSES/windows-strings-0.5.1/license-apache-2.0 +201 -0
  581. data/THIRD_PARTY_LICENSES/windows-strings-0.5.1/license-mit +21 -0
  582. data/THIRD_PARTY_LICENSES/windows-sys-0.61.2/license-apache-2.0 +201 -0
  583. data/THIRD_PARTY_LICENSES/windows-sys-0.61.2/license-mit +21 -0
  584. data/THIRD_PARTY_LICENSES/wit-bindgen-0.46.0/LICENSE-APACHE +201 -0
  585. data/THIRD_PARTY_LICENSES/wit-bindgen-0.46.0/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  586. data/THIRD_PARTY_LICENSES/wit-bindgen-0.46.0/LICENSE-MIT +23 -0
  587. data/THIRD_PARTY_LICENSES/wreq-0.16.1/LICENSE +202 -0
  588. data/THIRD_PARTY_LICENSES/wreq-proto-0.2.6/LICENSE +202 -0
  589. data/THIRD_PARTY_LICENSES/wreq-rt-0.2.2-rc.4/LICENSE +201 -0
  590. data/THIRD_PARTY_LICENSES/wreq-util-0.2.0/LICENSE +201 -0
  591. data/THIRD_PARTY_LICENSES/writeable-0.6.4/LICENSE +46 -0
  592. data/THIRD_PARTY_LICENSES/wyz-0.5.1/LICENSE.txt +21 -0
  593. data/THIRD_PARTY_LICENSES/yoke-0.8.3/LICENSE +46 -0
  594. data/THIRD_PARTY_LICENSES/yoke-derive-0.8.4/LICENSE +46 -0
  595. data/THIRD_PARTY_LICENSES/zerocopy-0.8.31/LICENSE-APACHE +202 -0
  596. data/THIRD_PARTY_LICENSES/zerocopy-0.8.31/LICENSE-BSD +24 -0
  597. data/THIRD_PARTY_LICENSES/zerocopy-0.8.31/LICENSE-MIT +26 -0
  598. data/THIRD_PARTY_LICENSES/zerocopy-derive-0.8.31/LICENSE-APACHE +202 -0
  599. data/THIRD_PARTY_LICENSES/zerocopy-derive-0.8.31/LICENSE-BSD +24 -0
  600. data/THIRD_PARTY_LICENSES/zerocopy-derive-0.8.31/LICENSE-MIT +26 -0
  601. data/THIRD_PARTY_LICENSES/zerofrom-0.1.6/LICENSE +46 -0
  602. data/THIRD_PARTY_LICENSES/zerofrom-derive-0.1.6/LICENSE +46 -0
  603. data/THIRD_PARTY_LICENSES/zerotrie-0.2.5/LICENSE +46 -0
  604. data/THIRD_PARTY_LICENSES/zerovec-0.11.8/LICENSE +46 -0
  605. data/THIRD_PARTY_LICENSES/zerovec-derive-0.11.6/LICENSE +46 -0
  606. data/THIRD_PARTY_LICENSES/zlib-rs-0.6.7/LICENSE +19 -0
  607. data/THIRD_PARTY_LICENSES/zmij-1.0.11/LICENSE-MIT +23 -0
  608. data/THIRD_PARTY_LICENSES/zstd-0.13.3/LICENSE +8 -0
  609. data/THIRD_PARTY_LICENSES/zstd-0.14.0/LICENSE +28 -0
  610. data/THIRD_PARTY_LICENSES/zstd-safe-7.3.0/LICENSE +28 -0
  611. data/THIRD_PARTY_LICENSES/zstd-safe-8.0.0/LICENSE +28 -0
  612. data/THIRD_PARTY_LICENSES/zstd-sys-2.1.0+zstd.1.5.7/LICENSE +28 -0
  613. data/THIRD_PARTY_LICENSES/zstd-sys-2.1.0+zstd.1.5.7/LICENSE.BSD-3-Clause +32 -0
  614. data/UPSTREAM.md +11 -0
  615. data/lib/cfsolve/cfsolve-engine +4 -0
  616. data/lib/cfsolve/profiles/safari-26-ios/answers.json +3606 -0
  617. data/lib/cfsolve/profiles/safari-26-ios/challenge-page-answers.json +3608 -0
  618. data/lib/cfsolve/profiles/safari-26-ios.json +554 -0
  619. data/lib/cfsolve/version.rb +6 -0
  620. data/lib/cfsolve.rb +113 -0
  621. metadata +702 -0
@@ -0,0 +1,4857 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ use crate::attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
6
+ use crate::attr::{NamespaceConstraint, ParsedAttrSelectorOperation, ParsedCaseSensitivity};
7
+ use crate::bloom::BLOOM_HASH_MASK;
8
+ use crate::builder::{
9
+ relative_selector_list_specificity_and_flags, selector_list_specificity_and_flags,
10
+ SelectorBuilder, SelectorFlags, Specificity, SpecificityAndFlags,
11
+ };
12
+ use crate::context::QuirksMode;
13
+ use crate::sink::Push;
14
+ use crate::visitor::SelectorListKind;
15
+ pub use crate::visitor::SelectorVisitor;
16
+ use bitflags::bitflags;
17
+ use cssparser::match_ignore_ascii_case;
18
+ use cssparser::parse_nth;
19
+ use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
20
+ use cssparser::{CowRcStr, Delimiter, SourceLocation};
21
+ use cssparser::{Parser as CssParser, ToCss, Token};
22
+ use debug_unreachable::debug_unreachable;
23
+ use precomputed_hash::PrecomputedHash;
24
+ use servo_arc::{Arc, ArcUnionBorrow, ThinArc, ThinArcUnion, UniqueArc};
25
+ use smallvec::SmallVec;
26
+ use std::borrow::{Borrow, Cow};
27
+ use std::fmt::{self, Debug};
28
+ use std::iter::Rev;
29
+ use std::slice;
30
+
31
+ #[cfg(feature = "to_shmem")]
32
+ use to_shmem_derive::ToShmem;
33
+
34
+ /// A trait that represents a pseudo-element.
35
+ pub trait PseudoElement: Sized + ToCss {
36
+ /// The `SelectorImpl` this pseudo-element is used for.
37
+ type Impl: SelectorImpl;
38
+
39
+ /// Whether the pseudo-element supports a given state selector to the right
40
+ /// of it.
41
+ fn accepts_state_pseudo_classes(&self) -> bool {
42
+ false
43
+ }
44
+
45
+ /// Whether this pseudo-element is valid after a ::slotted(..) pseudo.
46
+ fn valid_after_slotted(&self) -> bool {
47
+ false
48
+ }
49
+
50
+ /// Whether this pseudo-element is valid when directly after a ::before/::after pseudo.
51
+ fn valid_after_before_or_after(&self) -> bool {
52
+ false
53
+ }
54
+
55
+ /// Whether this pseudo-element is element-backed.
56
+ /// https://drafts.csswg.org/css-pseudo-4/#element-like
57
+ fn parses_as_element_backed(&self) -> bool {
58
+ false
59
+ }
60
+
61
+ /// Whether this pseudo-element is ::before or ::after pseudo element,
62
+ /// which are treated specially when deciding what can come after them.
63
+ /// https://drafts.csswg.org/css-pseudo-4/#generated-content
64
+ fn is_before_or_after(&self) -> bool {
65
+ false
66
+ }
67
+
68
+ /// The count we contribute to the specificity from this pseudo-element.
69
+ fn specificity_count(&self) -> u32 {
70
+ 1
71
+ }
72
+
73
+ /// Whether this pseudo-element is in a pseudo-element tree (excluding the pseudo-element
74
+ /// root).
75
+ /// https://drafts.csswg.org/css-view-transitions-1/#pseudo-root
76
+ fn is_in_pseudo_element_tree(&self) -> bool {
77
+ false
78
+ }
79
+ }
80
+
81
+ /// A trait that represents a pseudo-class.
82
+ pub trait NonTSPseudoClass: Sized + ToCss {
83
+ /// The `SelectorImpl` this pseudo-element is used for.
84
+ type Impl: SelectorImpl;
85
+
86
+ /// Whether this pseudo-class is :active or :hover.
87
+ fn is_active_or_hover(&self) -> bool;
88
+
89
+ /// Whether this pseudo-class belongs to:
90
+ ///
91
+ /// https://drafts.csswg.org/selectors-4/#useraction-pseudos
92
+ fn is_user_action_state(&self) -> bool;
93
+
94
+ fn visit<V>(&self, _visitor: &mut V) -> bool
95
+ where
96
+ V: SelectorVisitor<Impl = Self::Impl>,
97
+ {
98
+ true
99
+ }
100
+ }
101
+
102
+ /// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
103
+ /// Cow::Owned if `s` had to be converted into ASCII lowercase.
104
+ fn to_ascii_lowercase(s: &str) -> Cow<'_, str> {
105
+ if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
106
+ let mut string = s.to_owned();
107
+ string[first_uppercase..].make_ascii_lowercase();
108
+ string.into()
109
+ } else {
110
+ s.into()
111
+ }
112
+ }
113
+
114
+ bitflags! {
115
+ /// Flags that indicate at which point of parsing a selector are we.
116
+ #[derive(Copy, Clone)]
117
+ struct SelectorParsingState: u16 {
118
+ /// Whether we should avoid adding default namespaces to selectors that
119
+ /// aren't type or universal selectors.
120
+ const SKIP_DEFAULT_NAMESPACE = 1 << 0;
121
+
122
+ /// Whether we've parsed a ::slotted() pseudo-element already.
123
+ ///
124
+ /// If so, then we can only parse a subset of pseudo-elements, and
125
+ /// whatever comes after them if so.
126
+ const AFTER_SLOTTED = 1 << 1;
127
+ /// Whether we've parsed a ::part() or element-backed pseudo-element already.
128
+ ///
129
+ /// If so, then we can only parse a subset of pseudo-elements, and
130
+ /// whatever comes after them if so.
131
+ const AFTER_PART_LIKE = 1 << 2;
132
+ /// Whether we've parsed a non-element-backed pseudo-element (as in, an
133
+ /// `Impl::PseudoElement` thus not accounting for `::slotted` or
134
+ /// `::part`) already.
135
+ ///
136
+ /// If so, then other pseudo-elements and most other selectors are
137
+ /// disallowed.
138
+ const AFTER_NON_ELEMENT_BACKED_PSEUDO = 1 << 3;
139
+ /// Whether we've parsed a non-stateful pseudo-element (again, as-in
140
+ /// `Impl::PseudoElement`) already. If so, then other pseudo-classes are
141
+ /// disallowed. If this flag is set, `AFTER_NON_ELEMENT_BACKED_PSEUDO` must be set
142
+ /// as well.
143
+ const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
144
+ // Whether we've parsed a generated pseudo-element (as in ::before, ::after).
145
+ // If so then some other pseudo elements are disallowed (e.g. another generated pseudo)
146
+ // while others allowed (e.g. ::marker).
147
+ const AFTER_BEFORE_OR_AFTER_PSEUDO = 1 << 5;
148
+
149
+ /// Whether we are after any of the pseudo-like things.
150
+ const AFTER_PSEUDO = Self::AFTER_PART_LIKE.bits() | Self::AFTER_SLOTTED.bits() | Self::AFTER_NON_ELEMENT_BACKED_PSEUDO.bits() | Self::AFTER_BEFORE_OR_AFTER_PSEUDO.bits();
151
+
152
+ /// Whether we explicitly disallow combinators.
153
+ const DISALLOW_COMBINATORS = 1 << 6;
154
+
155
+ /// Whether we explicitly disallow pseudo-element-like things.
156
+ const DISALLOW_PSEUDOS = 1 << 7;
157
+
158
+ /// Whether we explicitly disallow relative selectors (i.e. `:has()`).
159
+ const DISALLOW_RELATIVE_SELECTOR = 1 << 8;
160
+
161
+ /// Whether we've parsed a pseudo-element which is in a pseudo-element tree (i.e. it is a
162
+ /// descendant pseudo of a pseudo-element root).
163
+ const IN_PSEUDO_ELEMENT_TREE = 1 << 9;
164
+ }
165
+ }
166
+
167
+ impl SelectorParsingState {
168
+ #[inline]
169
+ fn allows_slotted(self) -> bool {
170
+ !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
171
+ }
172
+
173
+ #[inline]
174
+ fn allows_part(self) -> bool {
175
+ !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
176
+ }
177
+
178
+ #[inline]
179
+ fn allows_non_functional_pseudo_classes(self) -> bool {
180
+ !self.intersects(Self::AFTER_SLOTTED | Self::AFTER_NON_STATEFUL_PSEUDO_ELEMENT)
181
+ }
182
+
183
+ #[inline]
184
+ fn allows_tree_structural_pseudo_classes(self) -> bool {
185
+ !self.intersects(Self::AFTER_PSEUDO) || self.intersects(Self::IN_PSEUDO_ELEMENT_TREE)
186
+ }
187
+
188
+ #[inline]
189
+ fn allows_combinators(self) -> bool {
190
+ !self.intersects(Self::DISALLOW_COMBINATORS)
191
+ }
192
+
193
+ #[inline]
194
+ fn allows_only_child_pseudo_class_only(self) -> bool {
195
+ self.intersects(Self::IN_PSEUDO_ELEMENT_TREE)
196
+ }
197
+ }
198
+
199
+ pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>;
200
+
201
+ #[derive(Clone, Debug, PartialEq)]
202
+ pub enum SelectorParseErrorKind<'i> {
203
+ NoQualifiedNameInAttributeSelector(Token<'i>),
204
+ EmptySelector,
205
+ DanglingCombinator,
206
+ NonCompoundSelector,
207
+ NonPseudoElementAfterSlotted,
208
+ InvalidPseudoElementAfterSlotted,
209
+ InvalidPseudoElementInsideWhere,
210
+ InvalidState,
211
+ UnexpectedTokenInAttributeSelector(Token<'i>),
212
+ PseudoElementExpectedColon(Token<'i>),
213
+ PseudoElementExpectedIdent(Token<'i>),
214
+ NoIdentForPseudo(Token<'i>),
215
+ UnsupportedPseudoClassOrElement(CowRcStr<'i>),
216
+ UnexpectedIdent(CowRcStr<'i>),
217
+ ExpectedNamespace(CowRcStr<'i>),
218
+ ExpectedBarInAttr(Token<'i>),
219
+ BadValueInAttr(Token<'i>),
220
+ InvalidQualNameInAttr(Token<'i>),
221
+ ExplicitNamespaceUnexpectedToken(Token<'i>),
222
+ ClassNeedsIdent(Token<'i>),
223
+ }
224
+
225
+ macro_rules! with_all_bounds {
226
+ (
227
+ [ $( $InSelector: tt )* ]
228
+ [ $( $CommonBounds: tt )* ]
229
+ [ $( $FromStr: tt )* ]
230
+ ) => {
231
+ /// This trait allows to define the parser implementation in regards
232
+ /// of pseudo-classes/elements
233
+ ///
234
+ /// NB: We need Clone so that we can derive(Clone) on struct with that
235
+ /// are parameterized on SelectorImpl. See
236
+ /// <https://github.com/rust-lang/rust/issues/26925>
237
+ pub trait SelectorImpl: Clone + Debug + Sized + 'static {
238
+ type ExtraMatchingData<'a>: Sized + Default;
239
+ type AttrValue: $($InSelector)*;
240
+ type Identifier: $($InSelector)* + PrecomputedHash;
241
+ type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName> + PrecomputedHash;
242
+ type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl> + PrecomputedHash;
243
+ type NamespacePrefix: $($InSelector)* + Default;
244
+ type BorrowedNamespaceUrl: ?Sized + Eq;
245
+ type BorrowedLocalName: ?Sized + Eq;
246
+
247
+ /// non tree-structural pseudo-classes
248
+ /// (see: https://drafts.csswg.org/selectors/#structural-pseudos)
249
+ type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass<Impl = Self>;
250
+
251
+ /// pseudo-elements
252
+ type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
253
+
254
+ /// Whether attribute hashes should be collected for filtering
255
+ /// purposes.
256
+ fn should_collect_attr_hash(_name: &Self::LocalName) -> bool {
257
+ false
258
+ }
259
+ }
260
+ }
261
+ }
262
+
263
+ macro_rules! with_bounds {
264
+ ( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
265
+ with_all_bounds! {
266
+ [$($CommonBounds)* + $($FromStr)* + ToCss]
267
+ [$($CommonBounds)*]
268
+ [$($FromStr)*]
269
+ }
270
+ }
271
+ }
272
+
273
+ with_bounds! {
274
+ [Clone + Eq]
275
+ [for<'a> From<&'a str>]
276
+ }
277
+
278
+ pub trait Parser<'i> {
279
+ type Impl: SelectorImpl;
280
+ type Error: 'i + From<SelectorParseErrorKind<'i>>;
281
+
282
+ /// Whether to parse the `::slotted()` pseudo-element.
283
+ fn parse_slotted(&self) -> bool {
284
+ false
285
+ }
286
+
287
+ /// Whether to parse the `::part()` pseudo-element.
288
+ fn parse_part(&self) -> bool {
289
+ false
290
+ }
291
+
292
+ /// Whether to parse the selector list of nth-child() or nth-last-child().
293
+ fn parse_nth_child_of(&self) -> bool {
294
+ false
295
+ }
296
+
297
+ /// Whether to parse `:is` and `:where` pseudo-classes.
298
+ fn parse_is_and_where(&self) -> bool {
299
+ false
300
+ }
301
+
302
+ /// Whether to parse the :has pseudo-class.
303
+ fn parse_has(&self) -> bool {
304
+ false
305
+ }
306
+
307
+ /// Whether to parse the '&' delimiter as a parent selector.
308
+ fn parse_parent_selector(&self) -> bool {
309
+ false
310
+ }
311
+
312
+ /// Whether the given function name is an alias for the `:is()` function.
313
+ fn is_is_alias(&self, _name: &str) -> bool {
314
+ false
315
+ }
316
+
317
+ /// Whether to parse the `:host` pseudo-class.
318
+ fn parse_host(&self) -> bool {
319
+ false
320
+ }
321
+
322
+ /// Whether to allow forgiving selector-list parsing.
323
+ fn allow_forgiving_selectors(&self) -> bool {
324
+ true
325
+ }
326
+
327
+ /// This function can return an "Err" pseudo-element in order to support CSS2.1
328
+ /// pseudo-elements.
329
+ fn parse_non_ts_pseudo_class(
330
+ &self,
331
+ location: SourceLocation,
332
+ name: CowRcStr<'i>,
333
+ ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
334
+ Err(
335
+ location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
336
+ name,
337
+ )),
338
+ )
339
+ }
340
+
341
+ fn parse_non_ts_functional_pseudo_class<'t>(
342
+ &self,
343
+ name: CowRcStr<'i>,
344
+ parser: &mut CssParser<'i, 't>,
345
+ _after_part: bool,
346
+ ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
347
+ Err(
348
+ parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
349
+ name,
350
+ )),
351
+ )
352
+ }
353
+
354
+ fn parse_pseudo_element(
355
+ &self,
356
+ location: SourceLocation,
357
+ name: CowRcStr<'i>,
358
+ ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
359
+ Err(
360
+ location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
361
+ name,
362
+ )),
363
+ )
364
+ }
365
+
366
+ fn parse_functional_pseudo_element<'t>(
367
+ &self,
368
+ name: CowRcStr<'i>,
369
+ arguments: &mut CssParser<'i, 't>,
370
+ ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
371
+ Err(
372
+ arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
373
+ name,
374
+ )),
375
+ )
376
+ }
377
+
378
+ fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
379
+ None
380
+ }
381
+
382
+ fn namespace_for_prefix(
383
+ &self,
384
+ _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix,
385
+ ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
386
+ None
387
+ }
388
+ }
389
+
390
+ /// A selector list is a tagged pointer with either a single selector, or a ThinArc<()> of multiple
391
+ /// selectors.
392
+ #[derive(Clone, Eq, Debug, PartialEq)]
393
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
394
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
395
+ pub struct SelectorList<Impl: SelectorImpl>(
396
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
397
+ ThinArcUnion<SpecificityAndFlags, Component<Impl>, (), Selector<Impl>>,
398
+ );
399
+
400
+ impl<Impl: SelectorImpl> SelectorList<Impl> {
401
+ /// See Arc::mark_as_intentionally_leaked
402
+ pub fn mark_as_intentionally_leaked(&self) {
403
+ if let ArcUnionBorrow::Second(ref list) = self.0.borrow() {
404
+ list.with_arc(|list| list.mark_as_intentionally_leaked())
405
+ }
406
+ self.slice()
407
+ .iter()
408
+ .for_each(|s| s.mark_as_intentionally_leaked())
409
+ }
410
+
411
+ pub fn from_one(selector: Selector<Impl>) -> Self {
412
+ #[cfg(debug_assertions)]
413
+ let selector_repr = unsafe { *(&selector as *const _ as *const usize) };
414
+ let list = Self(ThinArcUnion::from_first(selector.into_data()));
415
+ #[cfg(debug_assertions)]
416
+ debug_assert_eq!(
417
+ selector_repr,
418
+ unsafe { *(&list as *const _ as *const usize) },
419
+ "We rely on the same bit representation for the single selector variant"
420
+ );
421
+ list
422
+ }
423
+
424
+ pub fn from_iter(mut iter: impl ExactSizeIterator<Item = Selector<Impl>>) -> Self {
425
+ if iter.len() == 1 {
426
+ Self::from_one(iter.next().unwrap())
427
+ } else {
428
+ Self(ThinArcUnion::from_second(ThinArc::from_header_and_iter(
429
+ (),
430
+ iter,
431
+ )))
432
+ }
433
+ }
434
+
435
+ #[inline]
436
+ pub fn slice(&self) -> &[Selector<Impl>] {
437
+ match self.0.borrow() {
438
+ ArcUnionBorrow::First(..) => {
439
+ // SAFETY: see from_one.
440
+ let selector: &Selector<Impl> = unsafe { std::mem::transmute(self) };
441
+ std::slice::from_ref(selector)
442
+ },
443
+ ArcUnionBorrow::Second(list) => list.get().slice(),
444
+ }
445
+ }
446
+
447
+ #[inline]
448
+ pub fn len(&self) -> usize {
449
+ match self.0.borrow() {
450
+ ArcUnionBorrow::First(..) => 1,
451
+ ArcUnionBorrow::Second(list) => list.len(),
452
+ }
453
+ }
454
+
455
+ /// Returns the address on the heap of the ThinArc for memory reporting.
456
+ pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
457
+ match self.0.borrow() {
458
+ ArcUnionBorrow::First(s) => s.with_arc(|a| a.heap_ptr()),
459
+ ArcUnionBorrow::Second(s) => s.with_arc(|a| a.heap_ptr()),
460
+ }
461
+ }
462
+ }
463
+
464
+ /// Uniquely identify a selector based on its components, which is behind ThinArc and
465
+ /// is therefore stable.
466
+ #[derive(Clone, Copy, Hash, Eq, PartialEq)]
467
+ pub struct SelectorKey(usize);
468
+
469
+ impl SelectorKey {
470
+ /// Create a new key based on the given selector.
471
+ pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>) -> Self {
472
+ Self(selector.0.slice().as_ptr() as usize)
473
+ }
474
+ }
475
+
476
+ /// Whether or not we're using forgiving parsing mode
477
+ #[derive(PartialEq)]
478
+ enum ForgivingParsing {
479
+ /// Discard the entire selector list upon encountering any invalid selector.
480
+ /// This is the default behavior for almost all of CSS.
481
+ No,
482
+ /// Ignore invalid selectors, potentially creating an empty selector list.
483
+ ///
484
+ /// This is the error recovery mode of :is() and :where()
485
+ Yes,
486
+ }
487
+
488
+ /// Flag indicating if we're parsing relative selectors.
489
+ #[derive(Copy, Clone, PartialEq)]
490
+ pub enum ParseRelative {
491
+ /// Expect selectors to start with a combinator, assuming descendant combinator if not present.
492
+ ForHas,
493
+ /// Allow selectors to start with a combinator, prepending a parent selector if so. Do nothing
494
+ /// otherwise
495
+ ForNesting,
496
+ /// Allow selectors to start with a combinator, prepending a scope selector if so. Do nothing
497
+ /// otherwise
498
+ ForScope,
499
+ /// Treat as parse error if any selector begins with a combinator.
500
+ No,
501
+ }
502
+
503
+ impl<Impl: SelectorImpl> SelectorList<Impl> {
504
+ /// Returns a selector list with a single `:scope` selector (with specificity)
505
+ pub fn scope() -> Self {
506
+ Self::from_one(Selector::scope())
507
+ }
508
+ /// Returns a selector list with a single implicit `:scope` selector (no specificity)
509
+ pub fn implicit_scope() -> Self {
510
+ Self::from_one(Selector::implicit_scope())
511
+ }
512
+
513
+ /// Parse a comma-separated list of Selectors.
514
+ /// <https://drafts.csswg.org/selectors/#grouping>
515
+ ///
516
+ /// Return the Selectors or Err if there is an invalid selector.
517
+ pub fn parse<'i, 't, P>(
518
+ parser: &P,
519
+ input: &mut CssParser<'i, 't>,
520
+ parse_relative: ParseRelative,
521
+ ) -> Result<Self, ParseError<'i, P::Error>>
522
+ where
523
+ P: Parser<'i, Impl = Impl>,
524
+ {
525
+ Self::parse_with_state(
526
+ parser,
527
+ input,
528
+ SelectorParsingState::empty(),
529
+ ForgivingParsing::No,
530
+ parse_relative,
531
+ )
532
+ }
533
+
534
+ /// Same as `parse`, but disallow parsing of pseudo-elements.
535
+ pub fn parse_disallow_pseudo<'i, 't, P>(
536
+ parser: &P,
537
+ input: &mut CssParser<'i, 't>,
538
+ parse_relative: ParseRelative,
539
+ ) -> Result<Self, ParseError<'i, P::Error>>
540
+ where
541
+ P: Parser<'i, Impl = Impl>,
542
+ {
543
+ Self::parse_with_state(
544
+ parser,
545
+ input,
546
+ SelectorParsingState::DISALLOW_PSEUDOS,
547
+ ForgivingParsing::No,
548
+ parse_relative,
549
+ )
550
+ }
551
+
552
+ pub fn parse_forgiving<'i, 't, P>(
553
+ parser: &P,
554
+ input: &mut CssParser<'i, 't>,
555
+ parse_relative: ParseRelative,
556
+ ) -> Result<Self, ParseError<'i, P::Error>>
557
+ where
558
+ P: Parser<'i, Impl = Impl>,
559
+ {
560
+ Self::parse_with_state(
561
+ parser,
562
+ input,
563
+ SelectorParsingState::empty(),
564
+ ForgivingParsing::Yes,
565
+ parse_relative,
566
+ )
567
+ }
568
+
569
+ #[inline]
570
+ fn parse_with_state<'i, 't, P>(
571
+ parser: &P,
572
+ input: &mut CssParser<'i, 't>,
573
+ state: SelectorParsingState,
574
+ recovery: ForgivingParsing,
575
+ parse_relative: ParseRelative,
576
+ ) -> Result<Self, ParseError<'i, P::Error>>
577
+ where
578
+ P: Parser<'i, Impl = Impl>,
579
+ {
580
+ let mut values = SmallVec::<[_; 4]>::new();
581
+ let forgiving = recovery == ForgivingParsing::Yes && parser.allow_forgiving_selectors();
582
+ loop {
583
+ let selector = input.parse_until_before(Delimiter::Comma, |input| {
584
+ let start = input.position();
585
+ let mut selector = parse_selector(parser, input, state, parse_relative);
586
+ if forgiving && (selector.is_err() || input.expect_exhausted().is_err()) {
587
+ input.expect_no_error_token()?;
588
+ selector = Ok(Selector::new_invalid(input.slice_from(start)));
589
+ }
590
+ selector
591
+ })?;
592
+
593
+ values.push(selector);
594
+
595
+ match input.next() {
596
+ Ok(&Token::Comma) => {},
597
+ Ok(_) => unreachable!(),
598
+ Err(_) => break,
599
+ }
600
+ }
601
+ Ok(Self::from_iter(values.into_iter()))
602
+ }
603
+
604
+ /// Replaces the parent selector in all the items of the selector list.
605
+ pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
606
+ Self::from_iter(
607
+ self.slice()
608
+ .iter()
609
+ .map(|selector| selector.replace_parent_selector(parent)),
610
+ )
611
+ }
612
+
613
+ /// Creates a SelectorList from a Vec of selectors. Used in tests.
614
+ #[allow(dead_code)]
615
+ pub(crate) fn from_vec(v: Vec<Selector<Impl>>) -> Self {
616
+ SelectorList::from_iter(v.into_iter())
617
+ }
618
+ }
619
+
620
+ /// Parses one compound selector suitable for nested stuff like :-moz-any, etc.
621
+ fn parse_inner_compound_selector<'i, 't, P, Impl>(
622
+ parser: &P,
623
+ input: &mut CssParser<'i, 't>,
624
+ state: SelectorParsingState,
625
+ ) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
626
+ where
627
+ P: Parser<'i, Impl = Impl>,
628
+ Impl: SelectorImpl,
629
+ {
630
+ parse_selector(
631
+ parser,
632
+ input,
633
+ state | SelectorParsingState::DISALLOW_PSEUDOS | SelectorParsingState::DISALLOW_COMBINATORS,
634
+ ParseRelative::No,
635
+ )
636
+ }
637
+
638
+ /// Ancestor hashes for the bloom filter. We precompute these and store them
639
+ /// inline with selectors to optimize cache performance during matching.
640
+ /// This matters a lot.
641
+ ///
642
+ /// We use 4 hashes, which is copied from Gecko, who copied it from WebKit.
643
+ /// Note that increasing the number of hashes here will adversely affect the
644
+ /// cache hit when fast-rejecting long lists of Rules with inline hashes.
645
+ ///
646
+ /// Because the bloom filter only uses the bottom 24 bits of the hash, we pack
647
+ /// the fourth hash into the upper bits of the first three hashes in order to
648
+ /// shrink Rule (whose size matters a lot). This scheme minimizes the runtime
649
+ /// overhead of the packing for the first three hashes (we just need to mask
650
+ /// off the upper bits) at the expense of making the fourth somewhat more
651
+ /// complicated to assemble, because we often bail out before checking all the
652
+ /// hashes.
653
+ #[derive(Clone, Debug, Eq, PartialEq)]
654
+ pub struct AncestorHashes {
655
+ pub packed_hashes: [u32; 3],
656
+ }
657
+
658
+ pub(crate) fn collect_selector_hashes<'a, Impl: SelectorImpl, Iter>(
659
+ iter: Iter,
660
+ quirks_mode: QuirksMode,
661
+ hashes: &mut [u32; 4],
662
+ len: &mut usize,
663
+ create_inner_iterator: fn(&'a Selector<Impl>) -> Iter,
664
+ ) -> bool
665
+ where
666
+ Iter: Iterator<Item = &'a Component<Impl>>,
667
+ {
668
+ for component in iter {
669
+ let hash = match *component {
670
+ Component::LocalName(LocalName {
671
+ ref name,
672
+ ref lower_name,
673
+ }) => {
674
+ // Only insert the local-name into the filter if it's all
675
+ // lowercase. Otherwise we would need to test both hashes, and
676
+ // our data structures aren't really set up for that.
677
+ if name != lower_name {
678
+ continue;
679
+ }
680
+ name.precomputed_hash()
681
+ },
682
+ Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => {
683
+ url.precomputed_hash()
684
+ },
685
+ // In quirks mode, class and id selectors should match
686
+ // case-insensitively, so just avoid inserting them into the filter.
687
+ Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => id.precomputed_hash(),
688
+ Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
689
+ class.precomputed_hash()
690
+ },
691
+ Component::AttributeInNoNamespace { ref local_name, .. }
692
+ if Impl::should_collect_attr_hash(local_name) =>
693
+ {
694
+ // AttributeInNoNamespace is only used when local_name ==
695
+ // local_name_lower.
696
+ local_name.precomputed_hash()
697
+ },
698
+ Component::AttributeInNoNamespaceExists {
699
+ ref local_name,
700
+ ref local_name_lower,
701
+ ..
702
+ } => {
703
+ // Only insert the local-name into the filter if it's all
704
+ // lowercase. Otherwise we would need to test both hashes, and
705
+ // our data structures aren't really set up for that.
706
+ if local_name != local_name_lower || !Impl::should_collect_attr_hash(local_name) {
707
+ continue;
708
+ }
709
+ local_name.precomputed_hash()
710
+ },
711
+ Component::AttributeOther(ref selector) => {
712
+ if selector.local_name != selector.local_name_lower
713
+ || !Impl::should_collect_attr_hash(&selector.local_name)
714
+ {
715
+ continue;
716
+ }
717
+ selector.local_name.precomputed_hash()
718
+ },
719
+ Component::Is(ref list) | Component::Where(ref list) => {
720
+ // :where and :is OR their selectors, so we can't put any hash
721
+ // in the filter if there's more than one selector, as that'd
722
+ // exclude elements that may match one of the other selectors.
723
+ let slice = list.slice();
724
+ if slice.len() == 1
725
+ && !collect_selector_hashes(
726
+ create_inner_iterator(&slice[0]),
727
+ quirks_mode,
728
+ hashes,
729
+ len,
730
+ create_inner_iterator,
731
+ )
732
+ {
733
+ return false;
734
+ }
735
+ continue;
736
+ },
737
+ _ => continue,
738
+ };
739
+
740
+ hashes[*len] = hash & BLOOM_HASH_MASK;
741
+ *len += 1;
742
+ if *len == hashes.len() {
743
+ return false;
744
+ }
745
+ }
746
+ true
747
+ }
748
+
749
+ fn collect_ancestor_hashes<Impl: SelectorImpl>(
750
+ iter: SelectorIter<Impl>,
751
+ quirks_mode: QuirksMode,
752
+ hashes: &mut [u32; 4],
753
+ len: &mut usize,
754
+ ) {
755
+ collect_selector_hashes(AncestorIter::new(iter), quirks_mode, hashes, len, |s| {
756
+ AncestorIter(s.iter())
757
+ });
758
+ }
759
+
760
+ impl AncestorHashes {
761
+ pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self {
762
+ // Compute ancestor hashes for the bloom filter.
763
+ let mut hashes = [0u32; 4];
764
+ let mut len = 0;
765
+ collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len);
766
+ debug_assert!(len <= 4);
767
+
768
+ // Now, pack the fourth hash (if it exists) into the upper byte of each of
769
+ // the other three hashes.
770
+ if len == 4 {
771
+ let fourth = hashes[3];
772
+ hashes[0] |= (fourth & 0x000000ff) << 24;
773
+ hashes[1] |= (fourth & 0x0000ff00) << 16;
774
+ hashes[2] |= (fourth & 0x00ff0000) << 8;
775
+ }
776
+
777
+ AncestorHashes {
778
+ packed_hashes: [hashes[0], hashes[1], hashes[2]],
779
+ }
780
+ }
781
+
782
+ /// Returns the fourth hash, reassembled from parts.
783
+ pub fn fourth_hash(&self) -> u32 {
784
+ ((self.packed_hashes[0] & 0xff000000) >> 24)
785
+ | ((self.packed_hashes[1] & 0xff000000) >> 16)
786
+ | ((self.packed_hashes[2] & 0xff000000) >> 8)
787
+ }
788
+ }
789
+
790
+ #[inline]
791
+ pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
792
+ // Rust type’s default, not default namespace
793
+ Impl::NamespaceUrl::default()
794
+ }
795
+
796
+ pub(super) type SelectorData<Impl> = ThinArc<SpecificityAndFlags, Component<Impl>>;
797
+
798
+ /// Whether a selector may match a featureless host element, and whether it may match other
799
+ /// elements.
800
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
801
+ pub enum MatchesFeaturelessHost {
802
+ /// The selector may match a featureless host, but also a non-featureless element.
803
+ Yes,
804
+ /// The selector is guaranteed to never match a non-featureless host element.
805
+ Only,
806
+ /// The selector never matches a featureless host.
807
+ Never,
808
+ }
809
+
810
+ impl MatchesFeaturelessHost {
811
+ /// Whether we may match.
812
+ #[inline]
813
+ pub fn may_match(self) -> bool {
814
+ return !matches!(self, Self::Never);
815
+ }
816
+ }
817
+
818
+ /// A Selector stores a sequence of simple selectors and combinators. The
819
+ /// iterator classes allow callers to iterate at either the raw sequence level or
820
+ /// at the level of sequences of simple selectors separated by combinators. Most
821
+ /// callers want the higher-level iterator.
822
+ ///
823
+ /// We store compound selectors internally right-to-left (in matching order).
824
+ /// Additionally, we invert the order of top-level compound selectors so that
825
+ /// each one matches left-to-right. This is because matching namespace, local name,
826
+ /// id, and class are all relatively cheap, whereas matching pseudo-classes might
827
+ /// be expensive (depending on the pseudo-class). Since authors tend to put the
828
+ /// pseudo-classes on the right, it's faster to start matching on the left.
829
+ ///
830
+ /// This reordering doesn't change the semantics of selector matching, and we
831
+ /// handle it in to_css to make it invisible to serialization.
832
+ #[derive(Clone, Eq, PartialEq)]
833
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
834
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
835
+ #[repr(transparent)]
836
+ pub struct Selector<Impl: SelectorImpl>(
837
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))] SelectorData<Impl>,
838
+ );
839
+
840
+ impl<Impl: SelectorImpl> Selector<Impl> {
841
+ /// See Arc::mark_as_intentionally_leaked
842
+ pub fn mark_as_intentionally_leaked(&self) {
843
+ self.0.mark_as_intentionally_leaked()
844
+ }
845
+
846
+ fn scope() -> Self {
847
+ Self(ThinArc::from_header_and_iter(
848
+ SpecificityAndFlags {
849
+ specificity: Specificity::single_class_like().into(),
850
+ flags: SelectorFlags::HAS_SCOPE,
851
+ },
852
+ std::iter::once(Component::Scope),
853
+ ))
854
+ }
855
+
856
+ /// An implicit scope selector, much like :where(:scope).
857
+ fn implicit_scope() -> Self {
858
+ Self(ThinArc::from_header_and_iter(
859
+ SpecificityAndFlags {
860
+ specificity: 0,
861
+ flags: SelectorFlags::HAS_SCOPE,
862
+ },
863
+ std::iter::once(Component::ImplicitScope),
864
+ ))
865
+ }
866
+
867
+ #[inline]
868
+ pub fn specificity(&self) -> u32 {
869
+ self.0.header.specificity
870
+ }
871
+
872
+ #[inline]
873
+ pub(crate) fn flags(&self) -> SelectorFlags {
874
+ self.0.header.flags
875
+ }
876
+
877
+ #[inline]
878
+ pub fn has_pseudo_element(&self) -> bool {
879
+ self.flags().intersects(SelectorFlags::HAS_PSEUDO)
880
+ }
881
+
882
+ #[inline]
883
+ pub fn has_parent_selector(&self) -> bool {
884
+ self.flags().intersects(SelectorFlags::HAS_PARENT)
885
+ }
886
+
887
+ #[inline]
888
+ pub fn has_scope_selector(&self) -> bool {
889
+ self.flags().intersects(SelectorFlags::HAS_SCOPE)
890
+ }
891
+
892
+ #[inline]
893
+ pub fn is_slotted(&self) -> bool {
894
+ self.flags().intersects(SelectorFlags::HAS_SLOTTED)
895
+ }
896
+
897
+ #[inline]
898
+ pub fn is_part(&self) -> bool {
899
+ self.flags().intersects(SelectorFlags::HAS_PART)
900
+ }
901
+
902
+ #[inline]
903
+ pub fn parts(&self) -> Option<&[Impl::Identifier]> {
904
+ if !self.is_part() {
905
+ return None;
906
+ }
907
+
908
+ let mut iter = self.iter();
909
+ if self.has_pseudo_element() {
910
+ // Skip the pseudo-element.
911
+ for _ in &mut iter {}
912
+
913
+ let combinator = iter.next_sequence()?;
914
+ debug_assert_eq!(combinator, Combinator::PseudoElement);
915
+ }
916
+
917
+ for component in iter {
918
+ if let Component::Part(ref part) = *component {
919
+ return Some(part);
920
+ }
921
+ }
922
+
923
+ debug_assert!(false, "is_part() lied somehow?");
924
+ None
925
+ }
926
+
927
+ #[inline]
928
+ pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
929
+ if !self.has_pseudo_element() {
930
+ return None;
931
+ }
932
+
933
+ for component in self.iter() {
934
+ if let Component::PseudoElement(ref pseudo) = *component {
935
+ return Some(pseudo);
936
+ }
937
+ }
938
+
939
+ debug_assert!(false, "has_pseudo_element lied!");
940
+ None
941
+ }
942
+
943
+ #[inline]
944
+ pub fn pseudo_elements(&self) -> SmallVec<[&Impl::PseudoElement; 3]> {
945
+ let mut pseudos = SmallVec::new();
946
+
947
+ if !self.has_pseudo_element() {
948
+ return pseudos;
949
+ }
950
+
951
+ let mut iter = self.iter();
952
+ loop {
953
+ for component in &mut iter {
954
+ if let Component::PseudoElement(ref pseudo) = *component {
955
+ pseudos.push(pseudo);
956
+ }
957
+ }
958
+ match iter.next_sequence() {
959
+ Some(Combinator::PseudoElement) => {},
960
+ _ => break,
961
+ }
962
+ }
963
+
964
+ debug_assert!(!pseudos.is_empty(), "has_pseudo_element lied!");
965
+
966
+ pseudos
967
+ }
968
+
969
+ /// Whether this selector (pseudo-element part excluded) matches every element.
970
+ ///
971
+ /// Used for "pre-computed" pseudo-elements in components/style/stylist.rs
972
+ #[inline]
973
+ pub fn is_universal(&self) -> bool {
974
+ self.iter_raw_match_order().all(|c| {
975
+ matches!(
976
+ *c,
977
+ Component::ExplicitUniversalType
978
+ | Component::ExplicitAnyNamespace
979
+ | Component::Combinator(Combinator::PseudoElement)
980
+ | Component::PseudoElement(..)
981
+ )
982
+ })
983
+ }
984
+
985
+ /// Whether this selector may match a featureless shadow host, with no combinators to the
986
+ /// left, and optionally has a pseudo-element to the right.
987
+ #[inline]
988
+ pub fn matches_featureless_host(
989
+ &self,
990
+ scope_matches_featureless_host: bool,
991
+ ) -> MatchesFeaturelessHost {
992
+ let flags = self.flags();
993
+ if !flags.intersects(SelectorFlags::HAS_HOST | SelectorFlags::HAS_SCOPE) {
994
+ return MatchesFeaturelessHost::Never;
995
+ }
996
+
997
+ let mut iter = self.iter();
998
+ if flags.intersects(SelectorFlags::HAS_PSEUDO) {
999
+ for _ in &mut iter {
1000
+ // Skip over pseudo-elements
1001
+ }
1002
+ match iter.next_sequence() {
1003
+ Some(c) if c.is_pseudo_element() => {},
1004
+ _ => {
1005
+ debug_assert!(false, "Pseudo selector without pseudo combinator?");
1006
+ return MatchesFeaturelessHost::Never;
1007
+ },
1008
+ }
1009
+ }
1010
+
1011
+ let compound_matches = crate::matching::compound_matches_featureless_host(
1012
+ &mut iter,
1013
+ scope_matches_featureless_host,
1014
+ );
1015
+ if iter.next_sequence().is_some() {
1016
+ return MatchesFeaturelessHost::Never;
1017
+ }
1018
+ return compound_matches;
1019
+ }
1020
+
1021
+ /// Returns an iterator over this selector in matching order (right-to-left).
1022
+ /// When a combinator is reached, the iterator will return None, and
1023
+ /// next_sequence() may be called to continue to the next sequence.
1024
+ #[inline]
1025
+ pub fn iter(&self) -> SelectorIter<'_, Impl> {
1026
+ SelectorIter {
1027
+ iter: self.iter_raw_match_order(),
1028
+ next_combinator: None,
1029
+ }
1030
+ }
1031
+
1032
+ /// Same as `iter()`, but skips `RelativeSelectorAnchor` and its associated combinator.
1033
+ #[inline]
1034
+ pub fn iter_skip_relative_selector_anchor(&self) -> SelectorIter<'_, Impl> {
1035
+ if cfg!(debug_assertions) {
1036
+ let mut selector_iter = self.iter_raw_parse_order_from(0);
1037
+ assert!(
1038
+ matches!(
1039
+ selector_iter.next().unwrap(),
1040
+ Component::RelativeSelectorAnchor
1041
+ ),
1042
+ "Relative selector does not start with RelativeSelectorAnchor"
1043
+ );
1044
+ assert!(
1045
+ selector_iter.next().unwrap().is_combinator(),
1046
+ "Relative combinator does not exist"
1047
+ );
1048
+ }
1049
+
1050
+ SelectorIter {
1051
+ iter: self.0.slice()[..self.len() - 2].iter(),
1052
+ next_combinator: None,
1053
+ }
1054
+ }
1055
+
1056
+ /// Returns an iterator over this selector in matching order (right-to-left),
1057
+ /// skipping the rightmost |offset| Components.
1058
+ #[inline]
1059
+ pub fn iter_from(&self, offset: usize) -> SelectorIter<'_, Impl> {
1060
+ let iter = self.0.slice()[offset..].iter();
1061
+ SelectorIter {
1062
+ iter,
1063
+ next_combinator: None,
1064
+ }
1065
+ }
1066
+
1067
+ /// Returns the combinator at index `index` (zero-indexed from the right),
1068
+ /// or panics if the component is not a combinator.
1069
+ #[inline]
1070
+ pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
1071
+ match self.0.slice()[index] {
1072
+ Component::Combinator(c) => c,
1073
+ ref other => panic!(
1074
+ "Not a combinator: {:?}, {:?}, index: {}",
1075
+ other, self, index
1076
+ ),
1077
+ }
1078
+ }
1079
+
1080
+ /// Returns an iterator over the entire sequence of simple selectors and
1081
+ /// combinators, in matching order (from right to left).
1082
+ #[inline]
1083
+ pub fn iter_raw_match_order(&self) -> slice::Iter<'_, Component<Impl>> {
1084
+ self.0.slice().iter()
1085
+ }
1086
+
1087
+ /// Returns the combinator at index `index` (zero-indexed from the left),
1088
+ /// or panics if the component is not a combinator.
1089
+ #[inline]
1090
+ pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
1091
+ match self.0.slice()[self.len() - index - 1] {
1092
+ Component::Combinator(c) => c,
1093
+ ref other => panic!(
1094
+ "Not a combinator: {:?}, {:?}, index: {}",
1095
+ other, self, index
1096
+ ),
1097
+ }
1098
+ }
1099
+
1100
+ /// Returns an iterator over the sequence of simple selectors and
1101
+ /// combinators, in parse order (from left to right), starting from
1102
+ /// `offset`.
1103
+ #[inline]
1104
+ pub fn iter_raw_parse_order_from(
1105
+ &self,
1106
+ offset: usize,
1107
+ ) -> Rev<slice::Iter<'_, Component<Impl>>> {
1108
+ self.0.slice()[..self.len() - offset].iter().rev()
1109
+ }
1110
+
1111
+ /// Creates a Selector from a vec of Components, specified in parse order. Used in tests.
1112
+ #[allow(dead_code)]
1113
+ pub(crate) fn from_vec(
1114
+ vec: Vec<Component<Impl>>,
1115
+ specificity: u32,
1116
+ flags: SelectorFlags,
1117
+ ) -> Self {
1118
+ let mut builder = SelectorBuilder::default();
1119
+ for component in vec.into_iter() {
1120
+ if let Some(combinator) = component.as_combinator() {
1121
+ builder.push_combinator(combinator);
1122
+ } else {
1123
+ builder.push_simple_selector(component);
1124
+ }
1125
+ }
1126
+ let spec = SpecificityAndFlags { specificity, flags };
1127
+ Selector(builder.build_with_specificity_and_flags(spec, ParseRelative::No))
1128
+ }
1129
+
1130
+ #[inline]
1131
+ fn into_data(self) -> SelectorData<Impl> {
1132
+ self.0
1133
+ }
1134
+
1135
+ pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
1136
+ let parent_specificity_and_flags = selector_list_specificity_and_flags(
1137
+ parent.slice().iter(),
1138
+ /* for_nesting_parent = */ true,
1139
+ );
1140
+
1141
+ let mut specificity = Specificity::from(self.specificity());
1142
+ let mut flags = self.flags() - SelectorFlags::HAS_PARENT;
1143
+ let forbidden_flags = SelectorFlags::forbidden_for_nesting();
1144
+
1145
+ fn replace_parent_on_selector_list<Impl: SelectorImpl>(
1146
+ orig: &[Selector<Impl>],
1147
+ parent: &SelectorList<Impl>,
1148
+ specificity: &mut Specificity,
1149
+ flags: &mut SelectorFlags,
1150
+ propagate_specificity: bool,
1151
+ forbidden_flags: SelectorFlags,
1152
+ ) -> Option<SelectorList<Impl>> {
1153
+ if !orig.iter().any(|s| s.has_parent_selector()) {
1154
+ return None;
1155
+ }
1156
+
1157
+ let result =
1158
+ SelectorList::from_iter(orig.iter().map(|s| s.replace_parent_selector(parent)));
1159
+
1160
+ let result_specificity_and_flags = selector_list_specificity_and_flags(
1161
+ result.slice().iter(),
1162
+ /* for_nesting_parent = */ false,
1163
+ );
1164
+ if propagate_specificity {
1165
+ *specificity += Specificity::from(
1166
+ result_specificity_and_flags.specificity
1167
+ - selector_list_specificity_and_flags(
1168
+ orig.iter(),
1169
+ /* for_nesting_parent = */ false,
1170
+ )
1171
+ .specificity,
1172
+ );
1173
+ }
1174
+ flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1175
+ Some(result)
1176
+ }
1177
+
1178
+ fn replace_parent_on_relative_selector_list<Impl: SelectorImpl>(
1179
+ orig: &[RelativeSelector<Impl>],
1180
+ parent: &SelectorList<Impl>,
1181
+ specificity: &mut Specificity,
1182
+ flags: &mut SelectorFlags,
1183
+ forbidden_flags: SelectorFlags,
1184
+ ) -> Vec<RelativeSelector<Impl>> {
1185
+ let mut any = false;
1186
+
1187
+ let result = orig
1188
+ .iter()
1189
+ .map(|s| {
1190
+ if !s.selector.has_parent_selector() {
1191
+ return s.clone();
1192
+ }
1193
+ any = true;
1194
+ RelativeSelector {
1195
+ match_hint: s.match_hint,
1196
+ selector: s.selector.replace_parent_selector(parent),
1197
+ }
1198
+ })
1199
+ .collect();
1200
+
1201
+ if !any {
1202
+ return result;
1203
+ }
1204
+
1205
+ let result_specificity_and_flags = relative_selector_list_specificity_and_flags(
1206
+ &result, /* for_nesting_parent = */ false,
1207
+ );
1208
+ flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1209
+ *specificity += Specificity::from(
1210
+ result_specificity_and_flags.specificity
1211
+ - relative_selector_list_specificity_and_flags(
1212
+ orig, /* for_nesting_parent = */ false,
1213
+ )
1214
+ .specificity,
1215
+ );
1216
+ result
1217
+ }
1218
+
1219
+ fn replace_parent_on_selector<Impl: SelectorImpl>(
1220
+ orig: &Selector<Impl>,
1221
+ parent: &SelectorList<Impl>,
1222
+ specificity: &mut Specificity,
1223
+ flags: &mut SelectorFlags,
1224
+ forbidden_flags: SelectorFlags,
1225
+ ) -> Selector<Impl> {
1226
+ let new_selector = orig.replace_parent_selector(parent);
1227
+ *specificity += Specificity::from(new_selector.specificity() - orig.specificity());
1228
+ flags.insert(new_selector.flags() - forbidden_flags);
1229
+ new_selector
1230
+ }
1231
+
1232
+ if !self.has_parent_selector() {
1233
+ return self.clone();
1234
+ }
1235
+
1236
+ let iter = self.iter_raw_match_order().map(|component| {
1237
+ use self::Component::*;
1238
+ match *component {
1239
+ LocalName(..)
1240
+ | ID(..)
1241
+ | Class(..)
1242
+ | AttributeInNoNamespaceExists { .. }
1243
+ | AttributeInNoNamespace { .. }
1244
+ | AttributeOther(..)
1245
+ | ExplicitUniversalType
1246
+ | ExplicitAnyNamespace
1247
+ | ExplicitNoNamespace
1248
+ | DefaultNamespace(..)
1249
+ | Namespace(..)
1250
+ | Root
1251
+ | Empty
1252
+ | Scope
1253
+ | ImplicitScope
1254
+ | Nth(..)
1255
+ | NonTSPseudoClass(..)
1256
+ | PseudoElement(..)
1257
+ | Combinator(..)
1258
+ | Host(None)
1259
+ | Part(..)
1260
+ | Invalid(..)
1261
+ | RelativeSelectorAnchor => component.clone(),
1262
+ ParentSelector => {
1263
+ specificity += Specificity::from(parent_specificity_and_flags.specificity);
1264
+ flags.insert(parent_specificity_and_flags.flags - forbidden_flags);
1265
+ Is(parent.clone())
1266
+ },
1267
+ Negation(ref selectors) => {
1268
+ Negation(
1269
+ replace_parent_on_selector_list(
1270
+ selectors.slice(),
1271
+ parent,
1272
+ &mut specificity,
1273
+ &mut flags,
1274
+ /* propagate_specificity = */ true,
1275
+ forbidden_flags,
1276
+ )
1277
+ .unwrap_or_else(|| selectors.clone()),
1278
+ )
1279
+ },
1280
+ Is(ref selectors) => {
1281
+ Is(replace_parent_on_selector_list(
1282
+ selectors.slice(),
1283
+ parent,
1284
+ &mut specificity,
1285
+ &mut flags,
1286
+ /* propagate_specificity = */ true,
1287
+ forbidden_flags,
1288
+ )
1289
+ .unwrap_or_else(|| selectors.clone()))
1290
+ },
1291
+ Where(ref selectors) => {
1292
+ Where(
1293
+ replace_parent_on_selector_list(
1294
+ selectors.slice(),
1295
+ parent,
1296
+ &mut specificity,
1297
+ &mut flags,
1298
+ /* propagate_specificity = */ false,
1299
+ forbidden_flags,
1300
+ )
1301
+ .unwrap_or_else(|| selectors.clone()),
1302
+ )
1303
+ },
1304
+ Has(ref selectors) => Has(replace_parent_on_relative_selector_list(
1305
+ selectors,
1306
+ parent,
1307
+ &mut specificity,
1308
+ &mut flags,
1309
+ forbidden_flags,
1310
+ )
1311
+ .into_boxed_slice()),
1312
+
1313
+ Host(Some(ref selector)) => Host(Some(replace_parent_on_selector(
1314
+ selector,
1315
+ parent,
1316
+ &mut specificity,
1317
+ &mut flags,
1318
+ forbidden_flags,
1319
+ ))),
1320
+ NthOf(ref data) => {
1321
+ let selectors = replace_parent_on_selector_list(
1322
+ data.selectors(),
1323
+ parent,
1324
+ &mut specificity,
1325
+ &mut flags,
1326
+ /* propagate_specificity = */ true,
1327
+ forbidden_flags,
1328
+ );
1329
+ NthOf(match selectors {
1330
+ Some(s) => {
1331
+ NthOfSelectorData::new(data.nth_data(), s.slice().iter().cloned())
1332
+ },
1333
+ None => data.clone(),
1334
+ })
1335
+ },
1336
+ Slotted(ref selector) => Slotted(replace_parent_on_selector(
1337
+ selector,
1338
+ parent,
1339
+ &mut specificity,
1340
+ &mut flags,
1341
+ forbidden_flags,
1342
+ )),
1343
+ }
1344
+ });
1345
+ let mut items = UniqueArc::from_header_and_iter(Default::default(), iter);
1346
+ *items.header_mut() = SpecificityAndFlags {
1347
+ specificity: specificity.into(),
1348
+ flags,
1349
+ };
1350
+ Selector(items.shareable())
1351
+ }
1352
+
1353
+ /// Returns count of simple selectors and combinators in the Selector.
1354
+ #[inline]
1355
+ pub fn len(&self) -> usize {
1356
+ self.0.len()
1357
+ }
1358
+
1359
+ /// Returns the address on the heap of the ThinArc for memory reporting.
1360
+ pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
1361
+ self.0.heap_ptr()
1362
+ }
1363
+
1364
+ /// Traverse selector components inside `self`.
1365
+ ///
1366
+ /// Implementations of this method should call `SelectorVisitor` methods
1367
+ /// or other impls of `Visit` as appropriate based on the fields of `Self`.
1368
+ ///
1369
+ /// A return value of `false` indicates terminating the traversal.
1370
+ /// It should be propagated with an early return.
1371
+ /// On the contrary, `true` indicates that all fields of `self` have been traversed:
1372
+ ///
1373
+ /// ```rust,ignore
1374
+ /// if !visitor.visit_simple_selector(&self.some_simple_selector) {
1375
+ /// return false;
1376
+ /// }
1377
+ /// if !self.some_component.visit(visitor) {
1378
+ /// return false;
1379
+ /// }
1380
+ /// true
1381
+ /// ```
1382
+ pub fn visit<V>(&self, visitor: &mut V) -> bool
1383
+ where
1384
+ V: SelectorVisitor<Impl = Impl>,
1385
+ {
1386
+ let mut current = self.iter();
1387
+ let mut combinator = None;
1388
+ loop {
1389
+ if !visitor.visit_complex_selector(combinator) {
1390
+ return false;
1391
+ }
1392
+
1393
+ for selector in &mut current {
1394
+ if !selector.visit(visitor) {
1395
+ return false;
1396
+ }
1397
+ }
1398
+
1399
+ combinator = current.next_sequence();
1400
+ if combinator.is_none() {
1401
+ break;
1402
+ }
1403
+ }
1404
+
1405
+ true
1406
+ }
1407
+
1408
+ /// Parse a selector, without any pseudo-element.
1409
+ #[inline]
1410
+ pub fn parse<'i, 't, P>(
1411
+ parser: &P,
1412
+ input: &mut CssParser<'i, 't>,
1413
+ ) -> Result<Self, ParseError<'i, P::Error>>
1414
+ where
1415
+ P: Parser<'i, Impl = Impl>,
1416
+ {
1417
+ parse_selector(
1418
+ parser,
1419
+ input,
1420
+ SelectorParsingState::empty(),
1421
+ ParseRelative::No,
1422
+ )
1423
+ }
1424
+
1425
+ pub fn new_invalid(s: &str) -> Self {
1426
+ fn check_for_parent(input: &mut CssParser, has_parent: &mut bool) {
1427
+ while let Ok(t) = input.next() {
1428
+ match *t {
1429
+ Token::Function(_)
1430
+ | Token::ParenthesisBlock
1431
+ | Token::CurlyBracketBlock
1432
+ | Token::SquareBracketBlock => {
1433
+ let _ = input.parse_nested_block(
1434
+ |i| -> Result<(), ParseError<'_, BasicParseError>> {
1435
+ check_for_parent(i, has_parent);
1436
+ Ok(())
1437
+ },
1438
+ );
1439
+ },
1440
+ Token::Delim('&') => {
1441
+ *has_parent = true;
1442
+ },
1443
+ _ => {},
1444
+ }
1445
+ if *has_parent {
1446
+ break;
1447
+ }
1448
+ }
1449
+ }
1450
+ let mut has_parent = false;
1451
+ {
1452
+ let mut parser = cssparser::ParserInput::new(s);
1453
+ let mut parser = CssParser::new(&mut parser);
1454
+ check_for_parent(&mut parser, &mut has_parent);
1455
+ }
1456
+ Self(ThinArc::from_header_and_iter(
1457
+ SpecificityAndFlags {
1458
+ specificity: 0,
1459
+ flags: if has_parent {
1460
+ SelectorFlags::HAS_PARENT
1461
+ } else {
1462
+ SelectorFlags::empty()
1463
+ },
1464
+ },
1465
+ std::iter::once(Component::Invalid(Arc::new(String::from(s.trim())))),
1466
+ ))
1467
+ }
1468
+
1469
+ /// Is the compound starting at the offset the subject compound, or referring to its pseudo-element?
1470
+ pub fn is_rightmost(&self, offset: usize) -> bool {
1471
+ // There can really be only one pseudo-element, and it's not really valid for anything else to
1472
+ // follow it.
1473
+ offset == 0
1474
+ || matches!(
1475
+ self.combinator_at_match_order(offset - 1),
1476
+ Combinator::PseudoElement
1477
+ )
1478
+ }
1479
+ }
1480
+
1481
+ #[derive(Clone)]
1482
+ pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
1483
+ iter: slice::Iter<'a, Component<Impl>>,
1484
+ next_combinator: Option<Combinator>,
1485
+ }
1486
+
1487
+ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
1488
+ /// Prepares this iterator to point to the next sequence to the left,
1489
+ /// returning the combinator if the sequence was found.
1490
+ #[inline]
1491
+ pub fn next_sequence(&mut self) -> Option<Combinator> {
1492
+ self.next_combinator.take()
1493
+ }
1494
+
1495
+ #[inline]
1496
+ pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
1497
+ let first = match self.next() {
1498
+ Some(c) => c,
1499
+ // Note that this is the common path that we keep inline: the
1500
+ // pseudo-element not having anything to its right.
1501
+ None => return true,
1502
+ };
1503
+ self.matches_for_stateless_pseudo_element_internal(first)
1504
+ }
1505
+
1506
+ #[inline(never)]
1507
+ fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool {
1508
+ if !first.matches_for_stateless_pseudo_element() {
1509
+ return false;
1510
+ }
1511
+ for component in self {
1512
+ // The only other parser-allowed Components in this sequence are
1513
+ // state pseudo-classes, or one of the other things that can contain
1514
+ // them.
1515
+ if !component.matches_for_stateless_pseudo_element() {
1516
+ return false;
1517
+ }
1518
+ }
1519
+ true
1520
+ }
1521
+
1522
+ /// Returns remaining count of the simple selectors and combinators in the Selector.
1523
+ #[inline]
1524
+ pub fn selector_length(&self) -> usize {
1525
+ self.iter.len()
1526
+ }
1527
+ }
1528
+
1529
+ impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
1530
+ type Item = &'a Component<Impl>;
1531
+
1532
+ #[inline]
1533
+ fn next(&mut self) -> Option<Self::Item> {
1534
+ debug_assert!(
1535
+ self.next_combinator.is_none(),
1536
+ "You should call next_sequence!"
1537
+ );
1538
+ match *self.iter.next()? {
1539
+ Component::Combinator(c) => {
1540
+ self.next_combinator = Some(c);
1541
+ None
1542
+ },
1543
+ ref x => Some(x),
1544
+ }
1545
+ }
1546
+ }
1547
+
1548
+ impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
1549
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1550
+ let iter = self.iter.clone().rev();
1551
+ for component in iter {
1552
+ component.to_css(f)?
1553
+ }
1554
+ Ok(())
1555
+ }
1556
+ }
1557
+
1558
+ /// An iterator over all combinators in a selector. Does not traverse selectors within psuedoclasses.
1559
+ struct CombinatorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1560
+ impl<'a, Impl: 'a + SelectorImpl> CombinatorIter<'a, Impl> {
1561
+ fn new(inner: SelectorIter<'a, Impl>) -> Self {
1562
+ let mut result = CombinatorIter(inner);
1563
+ result.consume_non_combinators();
1564
+ result
1565
+ }
1566
+
1567
+ fn consume_non_combinators(&mut self) {
1568
+ while self.0.next().is_some() {}
1569
+ }
1570
+ }
1571
+
1572
+ impl<'a, Impl: SelectorImpl> Iterator for CombinatorIter<'a, Impl> {
1573
+ type Item = Combinator;
1574
+ fn next(&mut self) -> Option<Self::Item> {
1575
+ let result = self.0.next_sequence();
1576
+ self.consume_non_combinators();
1577
+ result
1578
+ }
1579
+ }
1580
+
1581
+ /// An iterator over all simple selectors belonging to ancestors.
1582
+ struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1583
+ impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
1584
+ /// Creates an AncestorIter. The passed-in iterator is assumed to point to
1585
+ /// the beginning of the child sequence, which will be skipped.
1586
+ fn new(inner: SelectorIter<'a, Impl>) -> Self {
1587
+ let mut result = AncestorIter(inner);
1588
+ result.skip_until_ancestor();
1589
+ result
1590
+ }
1591
+
1592
+ /// Skips a sequence of simple selectors and all subsequent sequences until
1593
+ /// a non-pseudo-element ancestor combinator is reached.
1594
+ fn skip_until_ancestor(&mut self) {
1595
+ loop {
1596
+ while self.0.next().is_some() {}
1597
+ // If this is ever changed to stop at the "pseudo-element"
1598
+ // combinator, we will need to fix the way we compute hashes for
1599
+ // revalidation selectors.
1600
+ if self.0.next_sequence().map_or(true, |x| {
1601
+ matches!(x, Combinator::Child | Combinator::Descendant)
1602
+ }) {
1603
+ break;
1604
+ }
1605
+ }
1606
+ }
1607
+ }
1608
+
1609
+ impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
1610
+ type Item = &'a Component<Impl>;
1611
+ fn next(&mut self) -> Option<Self::Item> {
1612
+ // Grab the next simple selector in the sequence if available.
1613
+ let next = self.0.next();
1614
+ if next.is_some() {
1615
+ return next;
1616
+ }
1617
+
1618
+ // See if there are more sequences. If so, skip any non-ancestor sequences.
1619
+ if let Some(combinator) = self.0.next_sequence() {
1620
+ if !matches!(combinator, Combinator::Child | Combinator::Descendant) {
1621
+ self.skip_until_ancestor();
1622
+ }
1623
+ }
1624
+
1625
+ self.0.next()
1626
+ }
1627
+ }
1628
+
1629
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1630
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1631
+ pub enum Combinator {
1632
+ Child, // >
1633
+ Descendant, // space
1634
+ NextSibling, // +
1635
+ LaterSibling, // ~
1636
+ /// A dummy combinator we use to the left of pseudo-elements.
1637
+ ///
1638
+ /// It serializes as the empty string, and acts effectively as a child
1639
+ /// combinator in most cases. If we ever actually start using a child
1640
+ /// combinator for this, we will need to fix up the way hashes are computed
1641
+ /// for revalidation selectors.
1642
+ PseudoElement,
1643
+ /// Another combinator used for ::slotted(), which represent the jump from
1644
+ /// a node to its assigned slot.
1645
+ SlotAssignment,
1646
+ /// Another combinator used for `::part()`, which represents the jump from
1647
+ /// the part to the containing shadow host.
1648
+ Part,
1649
+ }
1650
+
1651
+ impl Combinator {
1652
+ /// Returns true if this combinator is a child or descendant combinator.
1653
+ #[inline]
1654
+ pub fn is_ancestor(&self) -> bool {
1655
+ matches!(
1656
+ *self,
1657
+ Combinator::Child
1658
+ | Combinator::Descendant
1659
+ | Combinator::PseudoElement
1660
+ | Combinator::SlotAssignment
1661
+ )
1662
+ }
1663
+
1664
+ /// Returns true if this combinator is a pseudo-element combinator.
1665
+ #[inline]
1666
+ pub fn is_pseudo_element(&self) -> bool {
1667
+ matches!(*self, Combinator::PseudoElement)
1668
+ }
1669
+
1670
+ /// Returns true if this combinator is a next- or later-sibling combinator.
1671
+ #[inline]
1672
+ pub fn is_sibling(&self) -> bool {
1673
+ matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1674
+ }
1675
+ }
1676
+
1677
+ /// An enum for the different types of :nth- pseudoclasses
1678
+ #[derive(Copy, Clone, Eq, PartialEq)]
1679
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1680
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1681
+ pub enum NthType {
1682
+ Child,
1683
+ LastChild,
1684
+ OnlyChild,
1685
+ OfType,
1686
+ LastOfType,
1687
+ OnlyOfType,
1688
+ }
1689
+
1690
+ impl NthType {
1691
+ pub fn is_only(self) -> bool {
1692
+ self == Self::OnlyChild || self == Self::OnlyOfType
1693
+ }
1694
+
1695
+ pub fn is_of_type(self) -> bool {
1696
+ self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType
1697
+ }
1698
+
1699
+ pub fn is_from_end(self) -> bool {
1700
+ self == Self::LastChild || self == Self::LastOfType
1701
+ }
1702
+ }
1703
+
1704
+ /// The properties that comprise an An+B syntax
1705
+ #[derive(Copy, Clone, Eq, PartialEq, Debug)]
1706
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1707
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1708
+ pub struct AnPlusB(pub i32, pub i32);
1709
+
1710
+ impl AnPlusB {
1711
+ #[inline]
1712
+ pub fn matches_index(&self, i: i32) -> bool {
1713
+ // Is there a non-negative integer n such that An+B=i?
1714
+ match i.checked_sub(self.1) {
1715
+ None => false,
1716
+ Some(an) => match an.checked_div(self.0) {
1717
+ Some(n) => n >= 0 && self.0 * n == an,
1718
+ None /* a == 0 */ => an == 0,
1719
+ },
1720
+ }
1721
+ }
1722
+ }
1723
+
1724
+ impl ToCss for AnPlusB {
1725
+ /// Serialize <an+b> (part of the CSS Syntax spec).
1726
+ /// <https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value>
1727
+ #[inline]
1728
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1729
+ where
1730
+ W: fmt::Write,
1731
+ {
1732
+ match (self.0, self.1) {
1733
+ (0, 0) => dest.write_char('0'),
1734
+
1735
+ (1, 0) => dest.write_char('n'),
1736
+ (-1, 0) => dest.write_str("-n"),
1737
+ (_, 0) => write!(dest, "{}n", self.0),
1738
+
1739
+ (0, _) => write!(dest, "{}", self.1),
1740
+ (1, _) => write!(dest, "n{:+}", self.1),
1741
+ (-1, _) => write!(dest, "-n{:+}", self.1),
1742
+ (_, _) => write!(dest, "{}n{:+}", self.0, self.1),
1743
+ }
1744
+ }
1745
+ }
1746
+
1747
+ /// The properties that comprise an :nth- pseudoclass as of Selectors 3 (e.g.,
1748
+ /// nth-child(An+B)).
1749
+ /// https://www.w3.org/TR/selectors-3/#nth-child-pseudo
1750
+ #[derive(Copy, Clone, Eq, PartialEq)]
1751
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1752
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1753
+ pub struct NthSelectorData {
1754
+ pub ty: NthType,
1755
+ pub is_function: bool,
1756
+ pub an_plus_b: AnPlusB,
1757
+ }
1758
+
1759
+ impl NthSelectorData {
1760
+ /// Returns selector data for :only-{child,of-type}
1761
+ #[inline]
1762
+ pub const fn only(of_type: bool) -> Self {
1763
+ Self {
1764
+ ty: if of_type {
1765
+ NthType::OnlyOfType
1766
+ } else {
1767
+ NthType::OnlyChild
1768
+ },
1769
+ is_function: false,
1770
+ an_plus_b: AnPlusB(0, 1),
1771
+ }
1772
+ }
1773
+
1774
+ /// Returns selector data for :first-{child,of-type}
1775
+ #[inline]
1776
+ pub const fn first(of_type: bool) -> Self {
1777
+ Self {
1778
+ ty: if of_type {
1779
+ NthType::OfType
1780
+ } else {
1781
+ NthType::Child
1782
+ },
1783
+ is_function: false,
1784
+ an_plus_b: AnPlusB(0, 1),
1785
+ }
1786
+ }
1787
+
1788
+ /// Returns selector data for :last-{child,of-type}
1789
+ #[inline]
1790
+ pub const fn last(of_type: bool) -> Self {
1791
+ Self {
1792
+ ty: if of_type {
1793
+ NthType::LastOfType
1794
+ } else {
1795
+ NthType::LastChild
1796
+ },
1797
+ is_function: false,
1798
+ an_plus_b: AnPlusB(0, 1),
1799
+ }
1800
+ }
1801
+
1802
+ /// Returns true if this is an edge selector that is not `:*-of-type``
1803
+ #[inline]
1804
+ pub fn is_simple_edge(&self) -> bool {
1805
+ self.an_plus_b.0 == 0
1806
+ && self.an_plus_b.1 == 1
1807
+ && !self.ty.is_of_type()
1808
+ && !self.ty.is_only()
1809
+ }
1810
+
1811
+ /// Writes the beginning of the selector.
1812
+ #[inline]
1813
+ fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1814
+ dest.write_str(match self.ty {
1815
+ NthType::Child if self.is_function => ":nth-child(",
1816
+ NthType::Child => ":first-child",
1817
+ NthType::LastChild if self.is_function => ":nth-last-child(",
1818
+ NthType::LastChild => ":last-child",
1819
+ NthType::OfType if self.is_function => ":nth-of-type(",
1820
+ NthType::OfType => ":first-of-type",
1821
+ NthType::LastOfType if self.is_function => ":nth-last-of-type(",
1822
+ NthType::LastOfType => ":last-of-type",
1823
+ NthType::OnlyChild => ":only-child",
1824
+ NthType::OnlyOfType => ":only-of-type",
1825
+ })
1826
+ }
1827
+
1828
+ #[inline]
1829
+ fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1830
+ self.an_plus_b.to_css(dest)
1831
+ }
1832
+ }
1833
+
1834
+ /// The properties that comprise an :nth- pseudoclass as of Selectors 4 (e.g.,
1835
+ /// nth-child(An+B [of S]?)).
1836
+ /// https://www.w3.org/TR/selectors-4/#nth-child-pseudo
1837
+ #[derive(Clone, Eq, PartialEq)]
1838
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1839
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1840
+ pub struct NthOfSelectorData<Impl: SelectorImpl>(
1841
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))] ThinArc<NthSelectorData, Selector<Impl>>,
1842
+ );
1843
+
1844
+ impl<Impl: SelectorImpl> NthOfSelectorData<Impl> {
1845
+ /// Returns selector data for :nth-{,last-}{child,of-type}(An+B [of S])
1846
+ #[inline]
1847
+ pub fn new<I>(nth_data: &NthSelectorData, selectors: I) -> Self
1848
+ where
1849
+ I: Iterator<Item = Selector<Impl>> + ExactSizeIterator,
1850
+ {
1851
+ Self(ThinArc::from_header_and_iter(*nth_data, selectors))
1852
+ }
1853
+
1854
+ /// Returns the An+B part of the selector
1855
+ #[inline]
1856
+ pub fn nth_data(&self) -> &NthSelectorData {
1857
+ &self.0.header
1858
+ }
1859
+
1860
+ /// Returns the selector list part of the selector
1861
+ #[inline]
1862
+ pub fn selectors(&self) -> &[Selector<Impl>] {
1863
+ self.0.slice()
1864
+ }
1865
+ }
1866
+
1867
+ /// Flag indicating where a given relative selector's match would be contained.
1868
+ #[derive(Clone, Copy, Eq, PartialEq)]
1869
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1870
+ pub enum RelativeSelectorMatchHint {
1871
+ /// Within this element's subtree.
1872
+ InSubtree,
1873
+ /// Within this element's direct children.
1874
+ InChild,
1875
+ /// This element's next sibling.
1876
+ InNextSibling,
1877
+ /// Within this element's next sibling's subtree.
1878
+ InNextSiblingSubtree,
1879
+ /// Within this element's subsequent siblings.
1880
+ InSibling,
1881
+ /// Across this element's subsequent siblings and their subtrees.
1882
+ InSiblingSubtree,
1883
+ }
1884
+
1885
+ impl RelativeSelectorMatchHint {
1886
+ /// Create a new relative selector match hint based on its composition.
1887
+ pub fn new(
1888
+ relative_combinator: Combinator,
1889
+ has_child_or_descendants: bool,
1890
+ has_adjacent_or_next_siblings: bool,
1891
+ ) -> Self {
1892
+ match relative_combinator {
1893
+ Combinator::Descendant => RelativeSelectorMatchHint::InSubtree,
1894
+ Combinator::Child => {
1895
+ if !has_child_or_descendants {
1896
+ RelativeSelectorMatchHint::InChild
1897
+ } else {
1898
+ // Technically, for any composition that consists of child combinators only,
1899
+ // the search space is depth-constrained, but it's probably not worth optimizing for.
1900
+ RelativeSelectorMatchHint::InSubtree
1901
+ }
1902
+ },
1903
+ Combinator::NextSibling => {
1904
+ if !has_child_or_descendants && !has_adjacent_or_next_siblings {
1905
+ RelativeSelectorMatchHint::InNextSibling
1906
+ } else if !has_child_or_descendants && has_adjacent_or_next_siblings {
1907
+ RelativeSelectorMatchHint::InSibling
1908
+ } else if has_child_or_descendants && !has_adjacent_or_next_siblings {
1909
+ // Match won't cross multiple siblings.
1910
+ RelativeSelectorMatchHint::InNextSiblingSubtree
1911
+ } else {
1912
+ RelativeSelectorMatchHint::InSiblingSubtree
1913
+ }
1914
+ },
1915
+ Combinator::LaterSibling => {
1916
+ if !has_child_or_descendants {
1917
+ RelativeSelectorMatchHint::InSibling
1918
+ } else {
1919
+ // Even if the match may not cross multiple siblings, we have to look until
1920
+ // we find a match anyway.
1921
+ RelativeSelectorMatchHint::InSiblingSubtree
1922
+ }
1923
+ },
1924
+ Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1925
+ debug_assert!(false, "Unexpected relative combinator");
1926
+ RelativeSelectorMatchHint::InSubtree
1927
+ },
1928
+ }
1929
+ }
1930
+
1931
+ /// Is the match traversal direction towards the descendant of this element (As opposed to siblings)?
1932
+ pub fn is_descendant_direction(&self) -> bool {
1933
+ matches!(*self, Self::InChild | Self::InSubtree)
1934
+ }
1935
+
1936
+ /// Is the match traversal terminated at the next sibling?
1937
+ pub fn is_next_sibling(&self) -> bool {
1938
+ matches!(*self, Self::InNextSibling | Self::InNextSiblingSubtree)
1939
+ }
1940
+
1941
+ /// Does the match involve matching the subtree?
1942
+ pub fn is_subtree(&self) -> bool {
1943
+ matches!(
1944
+ *self,
1945
+ Self::InSubtree | Self::InSiblingSubtree | Self::InNextSiblingSubtree
1946
+ )
1947
+ }
1948
+ }
1949
+
1950
+ /// Count of combinators in a given relative selector, not traversing selectors of pseudoclasses.
1951
+ #[derive(Clone, Copy)]
1952
+ pub struct RelativeSelectorCombinatorCount {
1953
+ relative_combinator: Combinator,
1954
+ pub child_or_descendants: usize,
1955
+ pub adjacent_or_next_siblings: usize,
1956
+ }
1957
+
1958
+ impl RelativeSelectorCombinatorCount {
1959
+ /// Create a new relative selector combinator count from a given relative selector.
1960
+ pub fn new<Impl: SelectorImpl>(relative_selector: &RelativeSelector<Impl>) -> Self {
1961
+ let mut result = RelativeSelectorCombinatorCount {
1962
+ relative_combinator: relative_selector.selector.combinator_at_parse_order(1),
1963
+ child_or_descendants: 0,
1964
+ adjacent_or_next_siblings: 0,
1965
+ };
1966
+
1967
+ for combinator in CombinatorIter::new(
1968
+ relative_selector
1969
+ .selector
1970
+ .iter_skip_relative_selector_anchor(),
1971
+ ) {
1972
+ match combinator {
1973
+ Combinator::Descendant | Combinator::Child => {
1974
+ result.child_or_descendants += 1;
1975
+ },
1976
+ Combinator::NextSibling | Combinator::LaterSibling => {
1977
+ result.adjacent_or_next_siblings += 1;
1978
+ },
1979
+ Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1980
+ continue;
1981
+ },
1982
+ };
1983
+ }
1984
+ result
1985
+ }
1986
+
1987
+ /// Get the match hint based on the current combinator count.
1988
+ pub fn get_match_hint(&self) -> RelativeSelectorMatchHint {
1989
+ RelativeSelectorMatchHint::new(
1990
+ self.relative_combinator,
1991
+ self.child_or_descendants != 0,
1992
+ self.adjacent_or_next_siblings != 0,
1993
+ )
1994
+ }
1995
+ }
1996
+
1997
+ /// Storage for a relative selector.
1998
+ #[derive(Clone, Eq, PartialEq)]
1999
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2000
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2001
+ pub struct RelativeSelector<Impl: SelectorImpl> {
2002
+ /// Match space constraining hint.
2003
+ pub match_hint: RelativeSelectorMatchHint,
2004
+ /// The selector. Guaranteed to contain `RelativeSelectorAnchor` and the relative combinator in parse order.
2005
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2006
+ pub selector: Selector<Impl>,
2007
+ }
2008
+
2009
+ bitflags! {
2010
+ /// Composition of combinators in a given selector, not traversing selectors of pseudoclasses.
2011
+ #[derive(Clone, Debug, Eq, PartialEq)]
2012
+ struct CombinatorComposition: u8 {
2013
+ const DESCENDANTS = 1 << 0;
2014
+ const SIBLINGS = 1 << 1;
2015
+ }
2016
+ }
2017
+
2018
+ impl CombinatorComposition {
2019
+ fn for_relative_selector<Impl: SelectorImpl>(inner_selector: &Selector<Impl>) -> Self {
2020
+ let mut result = CombinatorComposition::empty();
2021
+ for combinator in CombinatorIter::new(inner_selector.iter_skip_relative_selector_anchor()) {
2022
+ match combinator {
2023
+ Combinator::Descendant | Combinator::Child => {
2024
+ result.insert(Self::DESCENDANTS);
2025
+ },
2026
+ Combinator::NextSibling | Combinator::LaterSibling => {
2027
+ result.insert(Self::SIBLINGS);
2028
+ },
2029
+ Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
2030
+ continue;
2031
+ },
2032
+ };
2033
+ if result.is_all() {
2034
+ break;
2035
+ }
2036
+ }
2037
+ return result;
2038
+ }
2039
+ }
2040
+
2041
+ impl<Impl: SelectorImpl> RelativeSelector<Impl> {
2042
+ fn from_selector_list(selector_list: SelectorList<Impl>) -> Box<[Self]> {
2043
+ selector_list
2044
+ .slice()
2045
+ .iter()
2046
+ .map(|selector| {
2047
+ // It's more efficient to keep track of all this during the parse time, but that seems like a lot of special
2048
+ // case handling for what it's worth.
2049
+ if cfg!(debug_assertions) {
2050
+ let relative_selector_anchor = selector.iter_raw_parse_order_from(0).next();
2051
+ debug_assert!(
2052
+ relative_selector_anchor.is_some(),
2053
+ "Relative selector is empty"
2054
+ );
2055
+ debug_assert!(
2056
+ matches!(
2057
+ relative_selector_anchor.unwrap(),
2058
+ Component::RelativeSelectorAnchor
2059
+ ),
2060
+ "Relative selector anchor is missing"
2061
+ );
2062
+ }
2063
+ // Leave a hint for narrowing down the search space when we're matching.
2064
+ let composition = CombinatorComposition::for_relative_selector(&selector);
2065
+ let match_hint = RelativeSelectorMatchHint::new(
2066
+ selector.combinator_at_parse_order(1),
2067
+ composition.intersects(CombinatorComposition::DESCENDANTS),
2068
+ composition.intersects(CombinatorComposition::SIBLINGS),
2069
+ );
2070
+ RelativeSelector {
2071
+ match_hint,
2072
+ selector: selector.clone(),
2073
+ }
2074
+ })
2075
+ .collect()
2076
+ }
2077
+ }
2078
+
2079
+ /// A CSS simple selector or combinator. We store both in the same enum for
2080
+ /// optimal packing and cache performance, see [1].
2081
+ ///
2082
+ /// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1357973
2083
+ #[derive(Clone, Eq, PartialEq)]
2084
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2085
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2086
+ pub enum Component<Impl: SelectorImpl> {
2087
+ LocalName(LocalName<Impl>),
2088
+
2089
+ ID(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2090
+ Class(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2091
+
2092
+ AttributeInNoNamespaceExists {
2093
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2094
+ local_name: Impl::LocalName,
2095
+ local_name_lower: Impl::LocalName,
2096
+ },
2097
+ // Used only when local_name is already lowercase.
2098
+ AttributeInNoNamespace {
2099
+ local_name: Impl::LocalName,
2100
+ operator: AttrSelectorOperator,
2101
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2102
+ value: Impl::AttrValue,
2103
+ case_sensitivity: ParsedCaseSensitivity,
2104
+ },
2105
+ // Use a Box in the less common cases with more data to keep size_of::<Component>() small.
2106
+ AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
2107
+
2108
+ ExplicitUniversalType,
2109
+ ExplicitAnyNamespace,
2110
+
2111
+ ExplicitNoNamespace,
2112
+ DefaultNamespace(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl),
2113
+ Namespace(
2114
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespacePrefix,
2115
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl,
2116
+ ),
2117
+
2118
+ /// Pseudo-classes
2119
+ Negation(SelectorList<Impl>),
2120
+ Root,
2121
+ Empty,
2122
+ Scope,
2123
+ /// :scope added implicitly into scoped rules (i.e. In `@scope`) not
2124
+ /// explicitly using `:scope` or `&` selectors.
2125
+ ///
2126
+ /// https://drafts.csswg.org/css-cascade-6/#scoped-rules
2127
+ ///
2128
+ /// Unlike the normal `:scope` selector, this does not add any specificity.
2129
+ /// See https://github.com/w3c/csswg-drafts/issues/10196
2130
+ ImplicitScope,
2131
+ ParentSelector,
2132
+ Nth(NthSelectorData),
2133
+ NthOf(NthOfSelectorData<Impl>),
2134
+ NonTSPseudoClass(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
2135
+ /// The ::slotted() pseudo-element:
2136
+ ///
2137
+ /// https://drafts.csswg.org/css-scoping/#slotted-pseudo
2138
+ ///
2139
+ /// The selector here is a compound selector, that is, no combinators.
2140
+ ///
2141
+ /// NOTE(emilio): This should support a list of selectors, but as of this
2142
+ /// writing no other browser does, and that allows them to put ::slotted()
2143
+ /// in the rule hash, so we do that too.
2144
+ ///
2145
+ /// See https://github.com/w3c/csswg-drafts/issues/2158
2146
+ Slotted(Selector<Impl>),
2147
+ /// The `::part` pseudo-element.
2148
+ /// https://drafts.csswg.org/css-shadow-parts/#part
2149
+ Part(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Box<[Impl::Identifier]>),
2150
+ /// The `:host` pseudo-class:
2151
+ ///
2152
+ /// https://drafts.csswg.org/css-scoping/#host-selector
2153
+ ///
2154
+ /// NOTE(emilio): This should support a list of selectors, but as of this
2155
+ /// writing no other browser does, and that allows them to put :host()
2156
+ /// in the rule hash, so we do that too.
2157
+ ///
2158
+ /// See https://github.com/w3c/csswg-drafts/issues/2158
2159
+ Host(Option<Selector<Impl>>),
2160
+ /// The `:where` pseudo-class.
2161
+ ///
2162
+ /// https://drafts.csswg.org/selectors/#zero-matches
2163
+ ///
2164
+ /// The inner argument is conceptually a SelectorList, but we move the
2165
+ /// selectors to the heap to keep Component small.
2166
+ Where(SelectorList<Impl>),
2167
+ /// The `:is` pseudo-class.
2168
+ ///
2169
+ /// https://drafts.csswg.org/selectors/#matches-pseudo
2170
+ ///
2171
+ /// Same comment as above re. the argument.
2172
+ Is(SelectorList<Impl>),
2173
+ /// The `:has` pseudo-class.
2174
+ ///
2175
+ /// https://drafts.csswg.org/selectors/#has-pseudo
2176
+ ///
2177
+ /// Same comment as above re. the argument.
2178
+ Has(Box<[RelativeSelector<Impl>]>),
2179
+ /// An invalid selector inside :is() / :where().
2180
+ Invalid(Arc<String>),
2181
+ /// An implementation-dependent pseudo-element selector.
2182
+ PseudoElement(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::PseudoElement),
2183
+
2184
+ Combinator(Combinator),
2185
+
2186
+ /// Used only for relative selectors, which starts with a combinator
2187
+ /// (With an implied descendant combinator if not specified).
2188
+ ///
2189
+ /// https://drafts.csswg.org/selectors-4/#typedef-relative-selector
2190
+ RelativeSelectorAnchor,
2191
+ }
2192
+
2193
+ impl<Impl: SelectorImpl> Component<Impl> {
2194
+ /// Returns true if this is a combinator.
2195
+ #[inline]
2196
+ pub fn is_combinator(&self) -> bool {
2197
+ matches!(*self, Component::Combinator(_))
2198
+ }
2199
+
2200
+ /// Returns true if this is a :host() selector.
2201
+ #[inline]
2202
+ pub fn is_host(&self) -> bool {
2203
+ matches!(*self, Component::Host(..))
2204
+ }
2205
+
2206
+ /// Returns the value as a combinator if applicable, None otherwise.
2207
+ pub fn as_combinator(&self) -> Option<Combinator> {
2208
+ match *self {
2209
+ Component::Combinator(c) => Some(c),
2210
+ _ => None,
2211
+ }
2212
+ }
2213
+
2214
+ /// Whether a given selector (to the right of a pseudo-element) should match for stateless
2215
+ /// pseudo-elements. Note that generally nothing matches for those, but since we have :not(),
2216
+ /// we still need to traverse nested selector lists.
2217
+ fn matches_for_stateless_pseudo_element(&self) -> bool {
2218
+ match *self {
2219
+ Component::Negation(ref selectors) => !selectors.slice().iter().all(|selector| {
2220
+ selector
2221
+ .iter_raw_match_order()
2222
+ .all(|c| c.matches_for_stateless_pseudo_element())
2223
+ }),
2224
+ Component::Is(ref selectors) | Component::Where(ref selectors) => {
2225
+ selectors.slice().iter().any(|selector| {
2226
+ selector
2227
+ .iter_raw_match_order()
2228
+ .all(|c| c.matches_for_stateless_pseudo_element())
2229
+ })
2230
+ },
2231
+ _ => false,
2232
+ }
2233
+ }
2234
+
2235
+ pub fn visit<V>(&self, visitor: &mut V) -> bool
2236
+ where
2237
+ V: SelectorVisitor<Impl = Impl>,
2238
+ {
2239
+ use self::Component::*;
2240
+ if !visitor.visit_simple_selector(self) {
2241
+ return false;
2242
+ }
2243
+
2244
+ match *self {
2245
+ Slotted(ref selector) => {
2246
+ if !selector.visit(visitor) {
2247
+ return false;
2248
+ }
2249
+ },
2250
+ Host(Some(ref selector)) => {
2251
+ if !selector.visit(visitor) {
2252
+ return false;
2253
+ }
2254
+ },
2255
+ AttributeInNoNamespaceExists {
2256
+ ref local_name,
2257
+ ref local_name_lower,
2258
+ } => {
2259
+ if !visitor.visit_attribute_selector(
2260
+ &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2261
+ local_name,
2262
+ local_name_lower,
2263
+ ) {
2264
+ return false;
2265
+ }
2266
+ },
2267
+ AttributeInNoNamespace { ref local_name, .. } => {
2268
+ if !visitor.visit_attribute_selector(
2269
+ &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2270
+ local_name,
2271
+ local_name,
2272
+ ) {
2273
+ return false;
2274
+ }
2275
+ },
2276
+ AttributeOther(ref attr_selector) => {
2277
+ let empty_string;
2278
+ let namespace = match attr_selector.namespace() {
2279
+ Some(ns) => ns,
2280
+ None => {
2281
+ empty_string = crate::parser::namespace_empty_string::<Impl>();
2282
+ NamespaceConstraint::Specific(&empty_string)
2283
+ },
2284
+ };
2285
+ if !visitor.visit_attribute_selector(
2286
+ &namespace,
2287
+ &attr_selector.local_name,
2288
+ &attr_selector.local_name_lower,
2289
+ ) {
2290
+ return false;
2291
+ }
2292
+ },
2293
+
2294
+ NonTSPseudoClass(ref pseudo_class) => {
2295
+ if !pseudo_class.visit(visitor) {
2296
+ return false;
2297
+ }
2298
+ },
2299
+ Negation(ref list) | Is(ref list) | Where(ref list) => {
2300
+ let list_kind = SelectorListKind::from_component(self);
2301
+ debug_assert!(!list_kind.is_empty());
2302
+ if !visitor.visit_selector_list(list_kind, list.slice()) {
2303
+ return false;
2304
+ }
2305
+ },
2306
+ NthOf(ref nth_of_data) => {
2307
+ if !visitor.visit_selector_list(SelectorListKind::NTH_OF, nth_of_data.selectors()) {
2308
+ return false;
2309
+ }
2310
+ },
2311
+ Has(ref list) => {
2312
+ if !visitor.visit_relative_selector_list(list) {
2313
+ return false;
2314
+ }
2315
+ },
2316
+ _ => {},
2317
+ }
2318
+
2319
+ true
2320
+ }
2321
+
2322
+ // Returns true if this has any selector that requires an index calculation. e.g.
2323
+ // :nth-child, :first-child, etc. For nested selectors, return true only if the
2324
+ // indexed selector is in its subject compound.
2325
+ pub fn has_indexed_selector_in_subject(&self) -> bool {
2326
+ match *self {
2327
+ Component::NthOf(..) | Component::Nth(..) => return true,
2328
+ Component::Is(ref selectors)
2329
+ | Component::Where(ref selectors)
2330
+ | Component::Negation(ref selectors) => {
2331
+ // Check the subject compound.
2332
+ for selector in selectors.slice() {
2333
+ let mut iter = selector.iter();
2334
+ while let Some(c) = iter.next() {
2335
+ if c.has_indexed_selector_in_subject() {
2336
+ return true;
2337
+ }
2338
+ }
2339
+ }
2340
+ },
2341
+ _ => (),
2342
+ };
2343
+ false
2344
+ }
2345
+ }
2346
+
2347
+ #[derive(Clone, Eq, PartialEq)]
2348
+ #[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2349
+ #[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2350
+ pub struct LocalName<Impl: SelectorImpl> {
2351
+ #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2352
+ pub name: Impl::LocalName,
2353
+ pub lower_name: Impl::LocalName,
2354
+ }
2355
+
2356
+ impl<Impl: SelectorImpl> Debug for Selector<Impl> {
2357
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2358
+ f.write_str("Selector(")?;
2359
+ self.to_css(f)?;
2360
+ write!(
2361
+ f,
2362
+ ", specificity = {:#x}, flags = {:?})",
2363
+ self.specificity(),
2364
+ self.flags()
2365
+ )
2366
+ }
2367
+ }
2368
+
2369
+ impl<Impl: SelectorImpl> Debug for Component<Impl> {
2370
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2371
+ self.to_css(f)
2372
+ }
2373
+ }
2374
+ impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
2375
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2376
+ self.to_css(f)
2377
+ }
2378
+ }
2379
+ impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
2380
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2381
+ self.to_css(f)
2382
+ }
2383
+ }
2384
+
2385
+ fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
2386
+ where
2387
+ Impl: SelectorImpl,
2388
+ I: Iterator<Item = &'a Selector<Impl>>,
2389
+ W: fmt::Write,
2390
+ {
2391
+ let mut first = true;
2392
+ for selector in iter {
2393
+ if !first {
2394
+ dest.write_str(", ")?;
2395
+ }
2396
+ first = false;
2397
+ selector.to_css(dest)?;
2398
+ }
2399
+ Ok(())
2400
+ }
2401
+
2402
+ impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
2403
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2404
+ where
2405
+ W: fmt::Write,
2406
+ {
2407
+ serialize_selector_list(self.slice().iter(), dest)
2408
+ }
2409
+ }
2410
+
2411
+ impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
2412
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2413
+ where
2414
+ W: fmt::Write,
2415
+ {
2416
+ // Compound selectors invert the order of their contents, so we need to
2417
+ // undo that during serialization.
2418
+ //
2419
+ // This two-iterator strategy involves walking over the selector twice.
2420
+ // We could do something more clever, but selector serialization probably
2421
+ // isn't hot enough to justify it, and the stringification likely
2422
+ // dominates anyway.
2423
+ //
2424
+ // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(),
2425
+ // which we need for |split|. So we split by combinators on a match-order
2426
+ // sequence and then reverse.
2427
+
2428
+ let mut combinators = self
2429
+ .iter_raw_match_order()
2430
+ .rev()
2431
+ .filter_map(|x| x.as_combinator());
2432
+ let compound_selectors = self
2433
+ .iter_raw_match_order()
2434
+ .as_slice()
2435
+ .split(|x| x.is_combinator())
2436
+ .rev();
2437
+
2438
+ let mut combinators_exhausted = false;
2439
+ for compound in compound_selectors {
2440
+ debug_assert!(!combinators_exhausted);
2441
+
2442
+ // https://drafts.csswg.org/cssom/#serializing-selectors
2443
+ let first_compound = match compound.first() {
2444
+ None => continue,
2445
+ Some(c) => c,
2446
+ };
2447
+ if matches!(
2448
+ first_compound,
2449
+ Component::RelativeSelectorAnchor | Component::ImplicitScope
2450
+ ) {
2451
+ debug_assert!(
2452
+ compound.len() == 1,
2453
+ "RelativeSelectorAnchor/ImplicitScope should only be a simple selector"
2454
+ );
2455
+ if let Some(c) = combinators.next() {
2456
+ c.to_css_relative(dest)?;
2457
+ } else {
2458
+ // Direct property declarations in `@scope` does not have
2459
+ // combinators, since its selector is `:implicit-scope`.
2460
+ debug_assert!(
2461
+ matches!(first_compound, Component::ImplicitScope),
2462
+ "Only implicit :scope may not have any combinator"
2463
+ );
2464
+ }
2465
+ continue;
2466
+ }
2467
+
2468
+ // 1. If there is only one simple selector in the compound selectors
2469
+ // which is a universal selector, append the result of
2470
+ // serializing the universal selector to s.
2471
+ //
2472
+ // Check if `!compound.empty()` first--this can happen if we have
2473
+ // something like `... > ::before`, because we store `>` and `::`
2474
+ // both as combinators internally.
2475
+ //
2476
+ // If we are in this case, after we have serialized the universal
2477
+ // selector, we skip Step 2 and continue with the algorithm.
2478
+ let (can_elide_namespace, first_non_namespace) = match compound[0] {
2479
+ Component::ExplicitAnyNamespace
2480
+ | Component::ExplicitNoNamespace
2481
+ | Component::Namespace(..) => (false, 1),
2482
+ Component::DefaultNamespace(..) => (true, 1),
2483
+ _ => (true, 0),
2484
+ };
2485
+ let mut perform_step_2 = true;
2486
+ let next_combinator = combinators.next();
2487
+ if first_non_namespace == compound.len() - 1 {
2488
+ match (next_combinator, &compound[first_non_namespace]) {
2489
+ // We have to be careful here, because if there is a
2490
+ // pseudo element "combinator" there isn't really just
2491
+ // the one simple selector. Technically this compound
2492
+ // selector contains the pseudo element selector as well
2493
+ // -- Combinator::PseudoElement, just like
2494
+ // Combinator::SlotAssignment, don't exist in the
2495
+ // spec.
2496
+ (Some(Combinator::PseudoElement), _)
2497
+ | (Some(Combinator::SlotAssignment), _) => (),
2498
+ (_, &Component::ExplicitUniversalType) => {
2499
+ // Iterate over everything so we serialize the namespace
2500
+ // too.
2501
+ for simple in compound.iter() {
2502
+ simple.to_css(dest)?;
2503
+ }
2504
+ // Skip step 2, which is an "otherwise".
2505
+ perform_step_2 = false;
2506
+ },
2507
+ _ => (),
2508
+ }
2509
+ }
2510
+
2511
+ // 2. Otherwise, for each simple selector in the compound selectors
2512
+ // that is not a universal selector of which the namespace prefix
2513
+ // maps to a namespace that is not the default namespace
2514
+ // serialize the simple selector and append the result to s.
2515
+ //
2516
+ // See https://github.com/w3c/csswg-drafts/issues/1606, which is
2517
+ // proposing to change this to match up with the behavior asserted
2518
+ // in cssom/serialize-namespaced-type-selectors.html, which the
2519
+ // following code tries to match.
2520
+ if perform_step_2 {
2521
+ for simple in compound.iter() {
2522
+ if let Component::ExplicitUniversalType = *simple {
2523
+ // Can't have a namespace followed by a pseudo-element
2524
+ // selector followed by a universal selector in the same
2525
+ // compound selector, so we don't have to worry about the
2526
+ // real namespace being in a different `compound`.
2527
+ if can_elide_namespace {
2528
+ continue;
2529
+ }
2530
+ }
2531
+ simple.to_css(dest)?;
2532
+ }
2533
+ }
2534
+
2535
+ // 3. If this is not the last part of the chain of the selector
2536
+ // append a single SPACE (U+0020), followed by the combinator
2537
+ // ">", "+", "~", ">>", "||", as appropriate, followed by another
2538
+ // single SPACE (U+0020) if the combinator was not whitespace, to
2539
+ // s.
2540
+ match next_combinator {
2541
+ Some(c) => c.to_css(dest)?,
2542
+ None => combinators_exhausted = true,
2543
+ };
2544
+
2545
+ // 4. If this is the last part of the chain of the selector and
2546
+ // there is a pseudo-element, append "::" followed by the name of
2547
+ // the pseudo-element, to s.
2548
+ //
2549
+ // (we handle this above)
2550
+ }
2551
+
2552
+ Ok(())
2553
+ }
2554
+ }
2555
+
2556
+ impl Combinator {
2557
+ fn to_css_internal<W>(&self, dest: &mut W, prefix_space: bool) -> fmt::Result
2558
+ where
2559
+ W: fmt::Write,
2560
+ {
2561
+ if matches!(
2562
+ *self,
2563
+ Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment
2564
+ ) {
2565
+ return Ok(());
2566
+ }
2567
+ if prefix_space {
2568
+ dest.write_char(' ')?;
2569
+ }
2570
+ match *self {
2571
+ Combinator::Child => dest.write_str("> "),
2572
+ Combinator::Descendant => Ok(()),
2573
+ Combinator::NextSibling => dest.write_str("+ "),
2574
+ Combinator::LaterSibling => dest.write_str("~ "),
2575
+ Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => unsafe {
2576
+ debug_unreachable!("Already handled")
2577
+ },
2578
+ }
2579
+ }
2580
+
2581
+ fn to_css_relative<W>(&self, dest: &mut W) -> fmt::Result
2582
+ where
2583
+ W: fmt::Write,
2584
+ {
2585
+ self.to_css_internal(dest, false)
2586
+ }
2587
+ }
2588
+
2589
+ impl ToCss for Combinator {
2590
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2591
+ where
2592
+ W: fmt::Write,
2593
+ {
2594
+ self.to_css_internal(dest, true)
2595
+ }
2596
+ }
2597
+
2598
+ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
2599
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2600
+ where
2601
+ W: fmt::Write,
2602
+ {
2603
+ use self::Component::*;
2604
+
2605
+ match *self {
2606
+ Combinator(ref c) => c.to_css(dest),
2607
+ Slotted(ref selector) => {
2608
+ dest.write_str("::slotted(")?;
2609
+ selector.to_css(dest)?;
2610
+ dest.write_char(')')
2611
+ },
2612
+ Part(ref part_names) => {
2613
+ dest.write_str("::part(")?;
2614
+ for (i, name) in part_names.iter().enumerate() {
2615
+ if i != 0 {
2616
+ dest.write_char(' ')?;
2617
+ }
2618
+ name.to_css(dest)?;
2619
+ }
2620
+ dest.write_char(')')
2621
+ },
2622
+ PseudoElement(ref p) => p.to_css(dest),
2623
+ ID(ref s) => {
2624
+ dest.write_char('#')?;
2625
+ s.to_css(dest)
2626
+ },
2627
+ Class(ref s) => {
2628
+ dest.write_char('.')?;
2629
+ s.to_css(dest)
2630
+ },
2631
+ LocalName(ref s) => s.to_css(dest),
2632
+ ExplicitUniversalType => dest.write_char('*'),
2633
+
2634
+ DefaultNamespace(_) => Ok(()),
2635
+ ExplicitNoNamespace => dest.write_char('|'),
2636
+ ExplicitAnyNamespace => dest.write_str("*|"),
2637
+ Namespace(ref prefix, _) => {
2638
+ prefix.to_css(dest)?;
2639
+ dest.write_char('|')
2640
+ },
2641
+
2642
+ AttributeInNoNamespaceExists { ref local_name, .. } => {
2643
+ dest.write_char('[')?;
2644
+ local_name.to_css(dest)?;
2645
+ dest.write_char(']')
2646
+ },
2647
+ AttributeInNoNamespace {
2648
+ ref local_name,
2649
+ operator,
2650
+ ref value,
2651
+ case_sensitivity,
2652
+ ..
2653
+ } => {
2654
+ dest.write_char('[')?;
2655
+ local_name.to_css(dest)?;
2656
+ operator.to_css(dest)?;
2657
+ value.to_css(dest)?;
2658
+ match case_sensitivity {
2659
+ ParsedCaseSensitivity::CaseSensitive
2660
+ | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2661
+ },
2662
+ ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2663
+ ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2664
+ }
2665
+ dest.write_char(']')
2666
+ },
2667
+ AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
2668
+
2669
+ // Pseudo-classes
2670
+ Root => dest.write_str(":root"),
2671
+ Empty => dest.write_str(":empty"),
2672
+ Scope => dest.write_str(":scope"),
2673
+ ParentSelector => dest.write_char('&'),
2674
+ Host(ref selector) => {
2675
+ dest.write_str(":host")?;
2676
+ if let Some(ref selector) = *selector {
2677
+ dest.write_char('(')?;
2678
+ selector.to_css(dest)?;
2679
+ dest.write_char(')')?;
2680
+ }
2681
+ Ok(())
2682
+ },
2683
+ Nth(ref nth_data) => {
2684
+ nth_data.write_start(dest)?;
2685
+ if nth_data.is_function {
2686
+ nth_data.write_affine(dest)?;
2687
+ dest.write_char(')')?;
2688
+ }
2689
+ Ok(())
2690
+ },
2691
+ NthOf(ref nth_of_data) => {
2692
+ let nth_data = nth_of_data.nth_data();
2693
+ nth_data.write_start(dest)?;
2694
+ debug_assert!(
2695
+ nth_data.is_function,
2696
+ "A selector must be a function to hold An+B notation"
2697
+ );
2698
+ nth_data.write_affine(dest)?;
2699
+ debug_assert!(
2700
+ matches!(nth_data.ty, NthType::Child | NthType::LastChild),
2701
+ "Only :nth-child or :nth-last-child can be of a selector list"
2702
+ );
2703
+ debug_assert!(
2704
+ !nth_of_data.selectors().is_empty(),
2705
+ "The selector list should not be empty"
2706
+ );
2707
+ dest.write_str(" of ")?;
2708
+ serialize_selector_list(nth_of_data.selectors().iter(), dest)?;
2709
+ dest.write_char(')')
2710
+ },
2711
+ Is(ref list) | Where(ref list) | Negation(ref list) => {
2712
+ match *self {
2713
+ Where(..) => dest.write_str(":where(")?,
2714
+ Is(..) => dest.write_str(":is(")?,
2715
+ Negation(..) => dest.write_str(":not(")?,
2716
+ _ => unreachable!(),
2717
+ }
2718
+ serialize_selector_list(list.slice().iter(), dest)?;
2719
+ dest.write_str(")")
2720
+ },
2721
+ Has(ref list) => {
2722
+ dest.write_str(":has(")?;
2723
+ serialize_selector_list(list.iter().map(|rel| &rel.selector), dest)?;
2724
+ dest.write_str(")")
2725
+ },
2726
+ NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
2727
+ Invalid(ref css) => dest.write_str(css),
2728
+ RelativeSelectorAnchor | ImplicitScope => Ok(()),
2729
+ }
2730
+ }
2731
+ }
2732
+
2733
+ impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
2734
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2735
+ where
2736
+ W: fmt::Write,
2737
+ {
2738
+ dest.write_char('[')?;
2739
+ match self.namespace {
2740
+ Some(NamespaceConstraint::Specific((ref prefix, _))) => {
2741
+ prefix.to_css(dest)?;
2742
+ dest.write_char('|')?
2743
+ },
2744
+ Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
2745
+ None => {},
2746
+ }
2747
+ self.local_name.to_css(dest)?;
2748
+ match self.operation {
2749
+ ParsedAttrSelectorOperation::Exists => {},
2750
+ ParsedAttrSelectorOperation::WithValue {
2751
+ operator,
2752
+ case_sensitivity,
2753
+ ref value,
2754
+ } => {
2755
+ operator.to_css(dest)?;
2756
+ value.to_css(dest)?;
2757
+ match case_sensitivity {
2758
+ ParsedCaseSensitivity::CaseSensitive
2759
+ | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2760
+ },
2761
+ ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2762
+ ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2763
+ }
2764
+ },
2765
+ }
2766
+ dest.write_char(']')
2767
+ }
2768
+ }
2769
+
2770
+ impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
2771
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2772
+ where
2773
+ W: fmt::Write,
2774
+ {
2775
+ self.name.to_css(dest)
2776
+ }
2777
+ }
2778
+
2779
+ /// Build up a Selector.
2780
+ /// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
2781
+ ///
2782
+ /// `Err` means invalid selector.
2783
+ fn parse_selector<'i, 't, P, Impl>(
2784
+ parser: &P,
2785
+ input: &mut CssParser<'i, 't>,
2786
+ mut state: SelectorParsingState,
2787
+ parse_relative: ParseRelative,
2788
+ ) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
2789
+ where
2790
+ P: Parser<'i, Impl = Impl>,
2791
+ Impl: SelectorImpl,
2792
+ {
2793
+ let mut builder = SelectorBuilder::default();
2794
+
2795
+ // Helps rewind less, but also simplifies dealing with relative combinators below.
2796
+ input.skip_whitespace();
2797
+
2798
+ if parse_relative != ParseRelative::No {
2799
+ let combinator = try_parse_combinator(input);
2800
+ match parse_relative {
2801
+ ParseRelative::ForHas => {
2802
+ builder.push_simple_selector(Component::RelativeSelectorAnchor);
2803
+ // Do we see a combinator? If so, push that. Otherwise, push a descendant
2804
+ // combinator.
2805
+ builder.push_combinator(combinator.unwrap_or(Combinator::Descendant));
2806
+ },
2807
+ ParseRelative::ForNesting | ParseRelative::ForScope => {
2808
+ if let Ok(combinator) = combinator {
2809
+ let selector = match parse_relative {
2810
+ ParseRelative::ForHas | ParseRelative::No => unreachable!(),
2811
+ ParseRelative::ForNesting => Component::ParentSelector,
2812
+ // See https://github.com/w3c/csswg-drafts/issues/10196
2813
+ // Implicitly added `:scope` does not add specificity
2814
+ // for non-relative selectors, so do the same.
2815
+ ParseRelative::ForScope => Component::ImplicitScope,
2816
+ };
2817
+ builder.push_simple_selector(selector);
2818
+ builder.push_combinator(combinator);
2819
+ }
2820
+ },
2821
+ ParseRelative::No => unreachable!(),
2822
+ }
2823
+ }
2824
+ loop {
2825
+ // Parse a sequence of simple selectors.
2826
+ let empty = parse_compound_selector(parser, &mut state, input, &mut builder)?;
2827
+ if empty {
2828
+ return Err(input.new_custom_error(if builder.has_combinators() {
2829
+ SelectorParseErrorKind::DanglingCombinator
2830
+ } else {
2831
+ SelectorParseErrorKind::EmptySelector
2832
+ }));
2833
+ }
2834
+
2835
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2836
+ debug_assert!(state.intersects(
2837
+ SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO
2838
+ | SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO
2839
+ | SelectorParsingState::AFTER_SLOTTED
2840
+ | SelectorParsingState::AFTER_PART_LIKE
2841
+ ));
2842
+ break;
2843
+ }
2844
+
2845
+ let combinator = if let Ok(c) = try_parse_combinator(input) {
2846
+ c
2847
+ } else {
2848
+ break;
2849
+ };
2850
+
2851
+ if !state.allows_combinators() {
2852
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2853
+ }
2854
+
2855
+ builder.push_combinator(combinator);
2856
+ }
2857
+ return Ok(Selector(builder.build(parse_relative)));
2858
+ }
2859
+
2860
+ fn try_parse_combinator<'i, 't>(input: &mut CssParser<'i, 't>) -> Result<Combinator, ()> {
2861
+ let mut any_whitespace = false;
2862
+ loop {
2863
+ let before_this_token = input.state();
2864
+ match input.next_including_whitespace() {
2865
+ Err(_e) => return Err(()),
2866
+ Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
2867
+ Ok(&Token::Delim('>')) => {
2868
+ return Ok(Combinator::Child);
2869
+ },
2870
+ Ok(&Token::Delim('+')) => {
2871
+ return Ok(Combinator::NextSibling);
2872
+ },
2873
+ Ok(&Token::Delim('~')) => {
2874
+ return Ok(Combinator::LaterSibling);
2875
+ },
2876
+ Ok(_) => {
2877
+ input.reset(&before_this_token);
2878
+ if any_whitespace {
2879
+ return Ok(Combinator::Descendant);
2880
+ } else {
2881
+ return Err(());
2882
+ }
2883
+ },
2884
+ }
2885
+ }
2886
+ }
2887
+
2888
+ /// * `Err(())`: Invalid selector, abort
2889
+ /// * `Ok(false)`: Not a type selector, could be something else. `input` was not consumed.
2890
+ /// * `Ok(true)`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
2891
+ fn parse_type_selector<'i, 't, P, Impl, S>(
2892
+ parser: &P,
2893
+ input: &mut CssParser<'i, 't>,
2894
+ state: SelectorParsingState,
2895
+ sink: &mut S,
2896
+ ) -> Result<bool, ParseError<'i, P::Error>>
2897
+ where
2898
+ P: Parser<'i, Impl = Impl>,
2899
+ Impl: SelectorImpl,
2900
+ S: Push<Component<Impl>>,
2901
+ {
2902
+ match parse_qualified_name(parser, input, /* in_attr_selector = */ false) {
2903
+ Err(ParseError {
2904
+ kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
2905
+ ..
2906
+ })
2907
+ | Ok(OptionalQName::None(_)) => Ok(false),
2908
+ Ok(OptionalQName::Some(namespace, local_name)) => {
2909
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2910
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2911
+ }
2912
+ match namespace {
2913
+ QNamePrefix::ImplicitAnyNamespace => {},
2914
+ QNamePrefix::ImplicitDefaultNamespace(url) => {
2915
+ sink.push(Component::DefaultNamespace(url))
2916
+ },
2917
+ QNamePrefix::ExplicitNamespace(prefix, url) => {
2918
+ sink.push(match parser.default_namespace() {
2919
+ Some(ref default_url) if url == *default_url => {
2920
+ Component::DefaultNamespace(url)
2921
+ },
2922
+ _ => Component::Namespace(prefix, url),
2923
+ })
2924
+ },
2925
+ QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
2926
+ QNamePrefix::ExplicitAnyNamespace => {
2927
+ match parser.default_namespace() {
2928
+ // Element type selectors that have no namespace
2929
+ // component (no namespace separator) represent elements
2930
+ // without regard to the element's namespace (equivalent
2931
+ // to "*|") unless a default namespace has been declared
2932
+ // for namespaced selectors (e.g. in CSS, in the style
2933
+ // sheet). If a default namespace has been declared,
2934
+ // such selectors will represent only elements in the
2935
+ // default namespace.
2936
+ // -- Selectors § 6.1.1
2937
+ // So we'll have this act the same as the
2938
+ // QNamePrefix::ImplicitAnyNamespace case.
2939
+ None => {},
2940
+ Some(_) => sink.push(Component::ExplicitAnyNamespace),
2941
+ }
2942
+ },
2943
+ QNamePrefix::ImplicitNoNamespace => {
2944
+ unreachable!() // Not returned with in_attr_selector = false
2945
+ },
2946
+ }
2947
+ match local_name {
2948
+ Some(name) => sink.push(Component::LocalName(LocalName {
2949
+ lower_name: to_ascii_lowercase(&name).as_ref().into(),
2950
+ name: name.as_ref().into(),
2951
+ })),
2952
+ None => sink.push(Component::ExplicitUniversalType),
2953
+ }
2954
+ Ok(true)
2955
+ },
2956
+ Err(e) => Err(e),
2957
+ }
2958
+ }
2959
+
2960
+ #[derive(Debug)]
2961
+ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
2962
+ SimpleSelector(Component<Impl>),
2963
+ PseudoElement(Impl::PseudoElement),
2964
+ SlottedPseudo(Selector<Impl>),
2965
+ PartPseudo(Box<[Impl::Identifier]>),
2966
+ }
2967
+
2968
+ #[derive(Debug)]
2969
+ enum QNamePrefix<Impl: SelectorImpl> {
2970
+ ImplicitNoNamespace, // `foo` in attr selectors
2971
+ ImplicitAnyNamespace, // `foo` in type selectors, without a default ns
2972
+ ImplicitDefaultNamespace(Impl::NamespaceUrl), // `foo` in type selectors, with a default ns
2973
+ ExplicitNoNamespace, // `|foo`
2974
+ ExplicitAnyNamespace, // `*|foo`
2975
+ ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo`
2976
+ }
2977
+
2978
+ enum OptionalQName<'i, Impl: SelectorImpl> {
2979
+ Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
2980
+ None(Token<'i>),
2981
+ }
2982
+
2983
+ /// * `Err(())`: Invalid selector, abort
2984
+ /// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed,
2985
+ /// but the token is still returned.
2986
+ /// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector
2987
+ fn parse_qualified_name<'i, 't, P, Impl>(
2988
+ parser: &P,
2989
+ input: &mut CssParser<'i, 't>,
2990
+ in_attr_selector: bool,
2991
+ ) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
2992
+ where
2993
+ P: Parser<'i, Impl = Impl>,
2994
+ Impl: SelectorImpl,
2995
+ {
2996
+ let default_namespace = |local_name| {
2997
+ let namespace = match parser.default_namespace() {
2998
+ Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
2999
+ None => QNamePrefix::ImplicitAnyNamespace,
3000
+ };
3001
+ Ok(OptionalQName::Some(namespace, local_name))
3002
+ };
3003
+
3004
+ let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
3005
+ let location = input.current_source_location();
3006
+ match input.next_including_whitespace() {
3007
+ Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
3008
+ Ok(&Token::Ident(ref local_name)) => {
3009
+ Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
3010
+ },
3011
+ Ok(t) if in_attr_selector => {
3012
+ let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
3013
+ Err(location.new_custom_error(e))
3014
+ },
3015
+ Ok(t) => Err(location.new_custom_error(
3016
+ SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()),
3017
+ )),
3018
+ Err(e) => Err(e.into()),
3019
+ }
3020
+ };
3021
+
3022
+ let start = input.state();
3023
+ match input.next_including_whitespace() {
3024
+ Ok(Token::Ident(value)) => {
3025
+ let value = value.clone();
3026
+ let after_ident = input.state();
3027
+ match input.next_including_whitespace() {
3028
+ Ok(&Token::Delim('|')) => {
3029
+ let prefix = value.as_ref().into();
3030
+ let result = parser.namespace_for_prefix(&prefix);
3031
+ let url = result.ok_or(
3032
+ after_ident
3033
+ .source_location()
3034
+ .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
3035
+ )?;
3036
+ explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
3037
+ },
3038
+ _ => {
3039
+ input.reset(&after_ident);
3040
+ if in_attr_selector {
3041
+ Ok(OptionalQName::Some(
3042
+ QNamePrefix::ImplicitNoNamespace,
3043
+ Some(value),
3044
+ ))
3045
+ } else {
3046
+ default_namespace(Some(value))
3047
+ }
3048
+ },
3049
+ }
3050
+ },
3051
+ Ok(Token::Delim('*')) => {
3052
+ let after_star = input.state();
3053
+ match input.next_including_whitespace() {
3054
+ Ok(&Token::Delim('|')) => {
3055
+ explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
3056
+ },
3057
+ _ if !in_attr_selector => {
3058
+ input.reset(&after_star);
3059
+ default_namespace(None)
3060
+ },
3061
+ result => {
3062
+ let t = result?;
3063
+ Err(after_star
3064
+ .source_location()
3065
+ .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t.clone())))
3066
+ },
3067
+ }
3068
+ },
3069
+ Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
3070
+ Ok(t) => {
3071
+ let t = t.clone();
3072
+ input.reset(&start);
3073
+ Ok(OptionalQName::None(t))
3074
+ },
3075
+ Err(e) => {
3076
+ input.reset(&start);
3077
+ Err(e.into())
3078
+ },
3079
+ }
3080
+ }
3081
+
3082
+ fn parse_attribute_selector<'i, 't, P, Impl>(
3083
+ parser: &P,
3084
+ input: &mut CssParser<'i, 't>,
3085
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3086
+ where
3087
+ P: Parser<'i, Impl = Impl>,
3088
+ Impl: SelectorImpl,
3089
+ {
3090
+ let namespace;
3091
+ let local_name;
3092
+
3093
+ input.skip_whitespace();
3094
+
3095
+ match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
3096
+ OptionalQName::None(t) => {
3097
+ return Err(input.new_custom_error(
3098
+ SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
3099
+ ));
3100
+ },
3101
+ OptionalQName::Some(_, None) => unreachable!(),
3102
+ OptionalQName::Some(ns, Some(ln)) => {
3103
+ local_name = ln;
3104
+ namespace = match ns {
3105
+ QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
3106
+ QNamePrefix::ExplicitNamespace(prefix, url) => {
3107
+ Some(NamespaceConstraint::Specific((prefix, url)))
3108
+ },
3109
+ QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
3110
+ QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
3111
+ unreachable!() // Not returned with in_attr_selector = true
3112
+ },
3113
+ }
3114
+ },
3115
+ }
3116
+
3117
+ let location = input.current_source_location();
3118
+ let operator = match input.next() {
3119
+ // [foo]
3120
+ Err(_) => {
3121
+ let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
3122
+ let local_name = local_name.as_ref().into();
3123
+ if let Some(namespace) = namespace {
3124
+ return Ok(Component::AttributeOther(Box::new(
3125
+ AttrSelectorWithOptionalNamespace {
3126
+ namespace: Some(namespace),
3127
+ local_name,
3128
+ local_name_lower,
3129
+ operation: ParsedAttrSelectorOperation::Exists,
3130
+ },
3131
+ )));
3132
+ } else {
3133
+ return Ok(Component::AttributeInNoNamespaceExists {
3134
+ local_name,
3135
+ local_name_lower,
3136
+ });
3137
+ }
3138
+ },
3139
+
3140
+ // [foo=bar]
3141
+ Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
3142
+ // [foo~=bar]
3143
+ Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
3144
+ // [foo|=bar]
3145
+ Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
3146
+ // [foo^=bar]
3147
+ Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
3148
+ // [foo*=bar]
3149
+ Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
3150
+ // [foo$=bar]
3151
+ Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
3152
+ Ok(t) => {
3153
+ return Err(location.new_custom_error(
3154
+ SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()),
3155
+ ));
3156
+ },
3157
+ };
3158
+
3159
+ let value = match input.expect_ident_or_string() {
3160
+ Ok(t) => t.clone(),
3161
+ Err(BasicParseError {
3162
+ kind: BasicParseErrorKind::UnexpectedToken(t),
3163
+ location,
3164
+ }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
3165
+ Err(e) => return Err(e.into()),
3166
+ };
3167
+
3168
+ let attribute_flags = parse_attribute_flags(input)?;
3169
+ let value = value.as_ref().into();
3170
+ let local_name_lower;
3171
+ let local_name_is_ascii_lowercase;
3172
+ let case_sensitivity;
3173
+ {
3174
+ let local_name_lower_cow = to_ascii_lowercase(&local_name);
3175
+ case_sensitivity =
3176
+ attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
3177
+ local_name_lower = local_name_lower_cow.as_ref().into();
3178
+ local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
3179
+ }
3180
+ let local_name = local_name.as_ref().into();
3181
+ if namespace.is_some() || !local_name_is_ascii_lowercase {
3182
+ Ok(Component::AttributeOther(Box::new(
3183
+ AttrSelectorWithOptionalNamespace {
3184
+ namespace,
3185
+ local_name,
3186
+ local_name_lower,
3187
+ operation: ParsedAttrSelectorOperation::WithValue {
3188
+ operator,
3189
+ case_sensitivity,
3190
+ value,
3191
+ },
3192
+ },
3193
+ )))
3194
+ } else {
3195
+ Ok(Component::AttributeInNoNamespace {
3196
+ local_name,
3197
+ operator,
3198
+ value,
3199
+ case_sensitivity,
3200
+ })
3201
+ }
3202
+ }
3203
+
3204
+ /// An attribute selector can have 's' or 'i' as flags, or no flags at all.
3205
+ enum AttributeFlags {
3206
+ // Matching should be case-sensitive ('s' flag).
3207
+ CaseSensitive,
3208
+ // Matching should be case-insensitive ('i' flag).
3209
+ AsciiCaseInsensitive,
3210
+ // No flags. Matching behavior depends on the name of the attribute.
3211
+ CaseSensitivityDependsOnName,
3212
+ }
3213
+
3214
+ impl AttributeFlags {
3215
+ fn to_case_sensitivity(
3216
+ self,
3217
+ local_name_lower: &str,
3218
+ have_namespace: bool,
3219
+ ) -> ParsedCaseSensitivity {
3220
+ match self {
3221
+ AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
3222
+ AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
3223
+ AttributeFlags::CaseSensitivityDependsOnName => {
3224
+ if !have_namespace
3225
+ && include!(concat!(
3226
+ env!("OUT_DIR"),
3227
+ "/ascii_case_insensitive_html_attributes.rs"
3228
+ ))
3229
+ .contains(local_name_lower)
3230
+ {
3231
+ ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
3232
+ } else {
3233
+ ParsedCaseSensitivity::CaseSensitive
3234
+ }
3235
+ },
3236
+ }
3237
+ }
3238
+ }
3239
+
3240
+ fn parse_attribute_flags<'i, 't>(
3241
+ input: &mut CssParser<'i, 't>,
3242
+ ) -> Result<AttributeFlags, BasicParseError<'i>> {
3243
+ let location = input.current_source_location();
3244
+ let token = match input.next() {
3245
+ Ok(t) => t,
3246
+ Err(..) => {
3247
+ // Selectors spec says language-defined; HTML says it depends on the
3248
+ // exact attribute name.
3249
+ return Ok(AttributeFlags::CaseSensitivityDependsOnName);
3250
+ },
3251
+ };
3252
+
3253
+ let ident = match *token {
3254
+ Token::Ident(ref i) => i,
3255
+ ref other => return Err(location.new_basic_unexpected_token_error(other.clone())),
3256
+ };
3257
+
3258
+ Ok(match_ignore_ascii_case! {
3259
+ ident,
3260
+ "i" => AttributeFlags::AsciiCaseInsensitive,
3261
+ "s" => AttributeFlags::CaseSensitive,
3262
+ _ => return Err(location.new_basic_unexpected_token_error(token.clone())),
3263
+ })
3264
+ }
3265
+
3266
+ /// Level 3: Parse **one** simple_selector. (Though we might insert a second
3267
+ /// implied "<defaultns>|*" type selector.)
3268
+ fn parse_negation<'i, 't, P, Impl>(
3269
+ parser: &P,
3270
+ input: &mut CssParser<'i, 't>,
3271
+ state: SelectorParsingState,
3272
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3273
+ where
3274
+ P: Parser<'i, Impl = Impl>,
3275
+ Impl: SelectorImpl,
3276
+ {
3277
+ let list = SelectorList::parse_with_state(
3278
+ parser,
3279
+ input,
3280
+ state
3281
+ | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3282
+ | SelectorParsingState::DISALLOW_PSEUDOS,
3283
+ ForgivingParsing::No,
3284
+ ParseRelative::No,
3285
+ )?;
3286
+
3287
+ Ok(Component::Negation(list))
3288
+ }
3289
+
3290
+ /// simple_selector_sequence
3291
+ /// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
3292
+ /// | [ HASH | class | attrib | pseudo | negation ]+
3293
+ ///
3294
+ /// `Err(())` means invalid selector.
3295
+ /// `Ok(true)` is an empty selector
3296
+ fn parse_compound_selector<'i, 't, P, Impl>(
3297
+ parser: &P,
3298
+ state: &mut SelectorParsingState,
3299
+ input: &mut CssParser<'i, 't>,
3300
+ builder: &mut SelectorBuilder<Impl>,
3301
+ ) -> Result<bool, ParseError<'i, P::Error>>
3302
+ where
3303
+ P: Parser<'i, Impl = Impl>,
3304
+ Impl: SelectorImpl,
3305
+ {
3306
+ input.skip_whitespace();
3307
+
3308
+ let mut empty = true;
3309
+ if parse_type_selector(parser, input, *state, builder)? {
3310
+ empty = false;
3311
+ }
3312
+
3313
+ loop {
3314
+ let result = match parse_one_simple_selector(parser, input, *state)? {
3315
+ None => break,
3316
+ Some(result) => result,
3317
+ };
3318
+
3319
+ if empty {
3320
+ if let Some(url) = parser.default_namespace() {
3321
+ // If there was no explicit type selector, but there is a
3322
+ // default namespace, there is an implicit "<defaultns>|*" type
3323
+ // selector. Except for :host() or :not() / :is() / :where(),
3324
+ // where we ignore it.
3325
+ //
3326
+ // https://drafts.csswg.org/css-scoping/#host-element-in-tree:
3327
+ //
3328
+ // When considered within its own shadow trees, the shadow
3329
+ // host is featureless. Only the :host, :host(), and
3330
+ // :host-context() pseudo-classes are allowed to match it.
3331
+ //
3332
+ // https://drafts.csswg.org/selectors-4/#featureless:
3333
+ //
3334
+ // A featureless element does not match any selector at all,
3335
+ // except those it is explicitly defined to match. If a
3336
+ // given selector is allowed to match a featureless element,
3337
+ // it must do so while ignoring the default namespace.
3338
+ //
3339
+ // https://drafts.csswg.org/selectors-4/#matches
3340
+ //
3341
+ // Default namespace declarations do not affect the compound
3342
+ // selector representing the subject of any selector within
3343
+ // a :is() pseudo-class, unless that compound selector
3344
+ // contains an explicit universal selector or type selector.
3345
+ //
3346
+ // (Similar quotes for :where() / :not())
3347
+ //
3348
+ let ignore_default_ns = state
3349
+ .intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE)
3350
+ || matches!(
3351
+ result,
3352
+ SimpleSelectorParseResult::SimpleSelector(Component::Host(..))
3353
+ );
3354
+ if !ignore_default_ns {
3355
+ builder.push_simple_selector(Component::DefaultNamespace(url));
3356
+ }
3357
+ }
3358
+ }
3359
+
3360
+ empty = false;
3361
+
3362
+ match result {
3363
+ SimpleSelectorParseResult::SimpleSelector(s) => {
3364
+ builder.push_simple_selector(s);
3365
+ },
3366
+ SimpleSelectorParseResult::PartPseudo(part_names) => {
3367
+ state.insert(SelectorParsingState::AFTER_PART_LIKE);
3368
+ builder.push_combinator(Combinator::Part);
3369
+ builder.push_simple_selector(Component::Part(part_names));
3370
+ },
3371
+ SimpleSelectorParseResult::SlottedPseudo(selector) => {
3372
+ state.insert(SelectorParsingState::AFTER_SLOTTED);
3373
+ builder.push_combinator(Combinator::SlotAssignment);
3374
+ builder.push_simple_selector(Component::Slotted(selector));
3375
+ },
3376
+ SimpleSelectorParseResult::PseudoElement(p) => {
3377
+ if p.parses_as_element_backed() {
3378
+ state.insert(SelectorParsingState::AFTER_PART_LIKE);
3379
+ } else {
3380
+ state.insert(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO);
3381
+ if p.is_before_or_after() {
3382
+ state.insert(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO);
3383
+ }
3384
+ }
3385
+ if !p.accepts_state_pseudo_classes() {
3386
+ state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
3387
+ }
3388
+ if p.is_in_pseudo_element_tree() {
3389
+ state.insert(SelectorParsingState::IN_PSEUDO_ELEMENT_TREE);
3390
+ }
3391
+ builder.push_combinator(Combinator::PseudoElement);
3392
+ builder.push_simple_selector(Component::PseudoElement(p));
3393
+ },
3394
+ }
3395
+ }
3396
+ Ok(empty)
3397
+ }
3398
+
3399
+ fn parse_is_where<'i, 't, P, Impl>(
3400
+ parser: &P,
3401
+ input: &mut CssParser<'i, 't>,
3402
+ state: SelectorParsingState,
3403
+ component: impl FnOnce(SelectorList<Impl>) -> Component<Impl>,
3404
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3405
+ where
3406
+ P: Parser<'i, Impl = Impl>,
3407
+ Impl: SelectorImpl,
3408
+ {
3409
+ debug_assert!(parser.parse_is_and_where());
3410
+ // https://drafts.csswg.org/selectors/#matches-pseudo:
3411
+ //
3412
+ // Pseudo-elements cannot be represented by the matches-any
3413
+ // pseudo-class; they are not valid within :is().
3414
+ //
3415
+ let inner = SelectorList::parse_with_state(
3416
+ parser,
3417
+ input,
3418
+ state
3419
+ | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3420
+ | SelectorParsingState::DISALLOW_PSEUDOS,
3421
+ ForgivingParsing::Yes,
3422
+ ParseRelative::No,
3423
+ )?;
3424
+ Ok(component(inner))
3425
+ }
3426
+
3427
+ fn parse_has<'i, 't, P, Impl>(
3428
+ parser: &P,
3429
+ input: &mut CssParser<'i, 't>,
3430
+ state: SelectorParsingState,
3431
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3432
+ where
3433
+ P: Parser<'i, Impl = Impl>,
3434
+ Impl: SelectorImpl,
3435
+ {
3436
+ debug_assert!(parser.parse_has());
3437
+ if state.intersects(
3438
+ SelectorParsingState::DISALLOW_RELATIVE_SELECTOR | SelectorParsingState::AFTER_PSEUDO,
3439
+ ) {
3440
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3441
+ }
3442
+ // Nested `:has()` is disallowed, mark it as such.
3443
+ // Note: The spec defines ":has-allowed pseudo-element," but there's no
3444
+ // pseudo-element defined as such at the moment.
3445
+ // https://w3c.github.io/csswg-drafts/selectors-4/#has-allowed-pseudo-element
3446
+ let inner = SelectorList::parse_with_state(
3447
+ parser,
3448
+ input,
3449
+ state
3450
+ | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3451
+ | SelectorParsingState::DISALLOW_PSEUDOS
3452
+ | SelectorParsingState::DISALLOW_RELATIVE_SELECTOR,
3453
+ ForgivingParsing::No,
3454
+ ParseRelative::ForHas,
3455
+ )?;
3456
+ Ok(Component::Has(RelativeSelector::from_selector_list(inner)))
3457
+ }
3458
+
3459
+ fn parse_functional_pseudo_class<'i, 't, P, Impl>(
3460
+ parser: &P,
3461
+ input: &mut CssParser<'i, 't>,
3462
+ name: CowRcStr<'i>,
3463
+ state: SelectorParsingState,
3464
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3465
+ where
3466
+ P: Parser<'i, Impl = Impl>,
3467
+ Impl: SelectorImpl,
3468
+ {
3469
+ match_ignore_ascii_case! { &name,
3470
+ "nth-child" => return parse_nth_pseudo_class(parser, input, state, NthType::Child),
3471
+ "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::OfType),
3472
+ "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, NthType::LastChild),
3473
+ "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::LastOfType),
3474
+ "is" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Is),
3475
+ "where" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Where),
3476
+ "has" if parser.parse_has() => return parse_has(parser, input, state),
3477
+ "host" => {
3478
+ if !state.allows_tree_structural_pseudo_classes() {
3479
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3480
+ }
3481
+ return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
3482
+ },
3483
+ "not" => {
3484
+ return parse_negation(parser, input, state)
3485
+ },
3486
+ _ => {}
3487
+ }
3488
+
3489
+ if parser.parse_is_and_where() && parser.is_is_alias(&name) {
3490
+ return parse_is_where(parser, input, state, Component::Is);
3491
+ }
3492
+
3493
+ if state.intersects(
3494
+ SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO | SelectorParsingState::AFTER_SLOTTED,
3495
+ ) {
3496
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3497
+ }
3498
+
3499
+ let after_part = state.intersects(SelectorParsingState::AFTER_PART_LIKE);
3500
+ P::parse_non_ts_functional_pseudo_class(parser, name, input, after_part)
3501
+ .map(Component::NonTSPseudoClass)
3502
+ }
3503
+
3504
+ fn parse_nth_pseudo_class<'i, 't, P, Impl>(
3505
+ parser: &P,
3506
+ input: &mut CssParser<'i, 't>,
3507
+ state: SelectorParsingState,
3508
+ ty: NthType,
3509
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3510
+ where
3511
+ P: Parser<'i, Impl = Impl>,
3512
+ Impl: SelectorImpl,
3513
+ {
3514
+ if !state.allows_tree_structural_pseudo_classes() {
3515
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3516
+ }
3517
+ let (a, b) = parse_nth(input)?;
3518
+ let nth_data = NthSelectorData {
3519
+ ty,
3520
+ is_function: true,
3521
+ an_plus_b: AnPlusB(a, b),
3522
+ };
3523
+ if !parser.parse_nth_child_of() || ty.is_of_type() {
3524
+ return Ok(Component::Nth(nth_data));
3525
+ }
3526
+
3527
+ // Try to parse "of <selector-list>".
3528
+ if input.try_parse(|i| i.expect_ident_matching("of")).is_err() {
3529
+ return Ok(Component::Nth(nth_data));
3530
+ }
3531
+ // Whitespace between "of" and the selector list is optional
3532
+ // https://github.com/w3c/csswg-drafts/issues/8285
3533
+ let selectors = SelectorList::parse_with_state(
3534
+ parser,
3535
+ input,
3536
+ state
3537
+ | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3538
+ | SelectorParsingState::DISALLOW_PSEUDOS,
3539
+ ForgivingParsing::No,
3540
+ ParseRelative::No,
3541
+ )?;
3542
+ Ok(Component::NthOf(NthOfSelectorData::new(
3543
+ &nth_data,
3544
+ selectors.slice().iter().cloned(),
3545
+ )))
3546
+ }
3547
+
3548
+ /// Returns whether the name corresponds to a CSS2 pseudo-element that
3549
+ /// can be specified with the single colon syntax (in addition to the
3550
+ /// double-colon syntax, which can be used for all pseudo-elements).
3551
+ pub fn is_css2_pseudo_element(name: &str) -> bool {
3552
+ // ** Do not add to this list! **
3553
+ match_ignore_ascii_case! { name,
3554
+ "before" | "after" | "first-line" | "first-letter" => true,
3555
+ _ => false,
3556
+ }
3557
+ }
3558
+
3559
+ /// Parse a simple selector other than a type selector.
3560
+ ///
3561
+ /// * `Err(())`: Invalid selector, abort
3562
+ /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed.
3563
+ /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
3564
+ fn parse_one_simple_selector<'i, 't, P, Impl>(
3565
+ parser: &P,
3566
+ input: &mut CssParser<'i, 't>,
3567
+ state: SelectorParsingState,
3568
+ ) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
3569
+ where
3570
+ P: Parser<'i, Impl = Impl>,
3571
+ Impl: SelectorImpl,
3572
+ {
3573
+ let start = input.state();
3574
+ let token = match input.next_including_whitespace().map(|t| t.clone()) {
3575
+ Ok(t) => t,
3576
+ Err(..) => {
3577
+ input.reset(&start);
3578
+ return Ok(None);
3579
+ },
3580
+ };
3581
+
3582
+ Ok(Some(match token {
3583
+ Token::IDHash(id) => {
3584
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3585
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3586
+ }
3587
+ let id = Component::ID(id.as_ref().into());
3588
+ SimpleSelectorParseResult::SimpleSelector(id)
3589
+ },
3590
+ Token::Delim(delim) if delim == '.' || (delim == '&' && parser.parse_parent_selector()) => {
3591
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3592
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3593
+ }
3594
+ let location = input.current_source_location();
3595
+ SimpleSelectorParseResult::SimpleSelector(if delim == '&' {
3596
+ Component::ParentSelector
3597
+ } else {
3598
+ let class = match *input.next_including_whitespace()? {
3599
+ Token::Ident(ref class) => class,
3600
+ ref t => {
3601
+ let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
3602
+ return Err(location.new_custom_error(e));
3603
+ },
3604
+ };
3605
+ Component::Class(class.as_ref().into())
3606
+ })
3607
+ },
3608
+ Token::SquareBracketBlock => {
3609
+ if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3610
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3611
+ }
3612
+ let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
3613
+ SimpleSelectorParseResult::SimpleSelector(attr)
3614
+ },
3615
+ Token::Colon => {
3616
+ let location = input.current_source_location();
3617
+ let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
3618
+ Token::Colon => (false, input.next_including_whitespace()?.clone()),
3619
+ t => (true, t),
3620
+ };
3621
+ let (name, is_functional) = match next_token {
3622
+ Token::Ident(name) => (name, false),
3623
+ Token::Function(name) => (name, true),
3624
+ t => {
3625
+ let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t);
3626
+ return Err(input.new_custom_error(e));
3627
+ },
3628
+ };
3629
+ let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
3630
+ if is_pseudo_element {
3631
+ // Pseudos after pseudo elements are not allowed in some cases:
3632
+ // - Some states will disallow pseudos, such as the interiors of
3633
+ // :has/:is/:where/:not (DISALLOW_PSEUDOS).
3634
+ // - Non-element backed pseudos do not allow other pseudos to follow (AFTER_NON_ELEMENT_BACKED_PSEUDO)...
3635
+ // - ... except ::before and ::after, which allow _some_ pseudos.
3636
+ if state.intersects(SelectorParsingState::DISALLOW_PSEUDOS)
3637
+ || (state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3638
+ && !state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO))
3639
+ {
3640
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3641
+ }
3642
+ let pseudo_element = if is_functional {
3643
+ if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
3644
+ if !state.allows_part() {
3645
+ return Err(
3646
+ input.new_custom_error(SelectorParseErrorKind::InvalidState)
3647
+ );
3648
+ }
3649
+ let names = input.parse_nested_block(|input| {
3650
+ let mut result = Vec::with_capacity(1);
3651
+ result.push(input.expect_ident()?.as_ref().into());
3652
+ while !input.is_exhausted() {
3653
+ result.push(input.expect_ident()?.as_ref().into());
3654
+ }
3655
+ Ok(result.into_boxed_slice())
3656
+ })?;
3657
+ return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
3658
+ }
3659
+ if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
3660
+ if !state.allows_slotted() {
3661
+ return Err(
3662
+ input.new_custom_error(SelectorParseErrorKind::InvalidState)
3663
+ );
3664
+ }
3665
+ let selector = input.parse_nested_block(|input| {
3666
+ parse_inner_compound_selector(parser, input, state)
3667
+ })?;
3668
+ return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
3669
+ }
3670
+ input.parse_nested_block(|input| {
3671
+ P::parse_functional_pseudo_element(parser, name, input)
3672
+ })?
3673
+ } else {
3674
+ P::parse_pseudo_element(parser, location, name)?
3675
+ };
3676
+
3677
+ if state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO)
3678
+ && !pseudo_element.valid_after_before_or_after()
3679
+ {
3680
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3681
+ }
3682
+
3683
+ if state.intersects(SelectorParsingState::AFTER_SLOTTED)
3684
+ && !pseudo_element.valid_after_slotted()
3685
+ {
3686
+ return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3687
+ }
3688
+ SimpleSelectorParseResult::PseudoElement(pseudo_element)
3689
+ } else {
3690
+ let pseudo_class = if is_functional {
3691
+ input.parse_nested_block(|input| {
3692
+ parse_functional_pseudo_class(parser, input, name, state)
3693
+ })?
3694
+ } else {
3695
+ parse_simple_pseudo_class(parser, location, name, state)?
3696
+ };
3697
+ SimpleSelectorParseResult::SimpleSelector(pseudo_class)
3698
+ }
3699
+ },
3700
+ _ => {
3701
+ input.reset(&start);
3702
+ return Ok(None);
3703
+ },
3704
+ }))
3705
+ }
3706
+
3707
+ fn parse_simple_pseudo_class<'i, P, Impl>(
3708
+ parser: &P,
3709
+ location: SourceLocation,
3710
+ name: CowRcStr<'i>,
3711
+ state: SelectorParsingState,
3712
+ ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3713
+ where
3714
+ P: Parser<'i, Impl = Impl>,
3715
+ Impl: SelectorImpl,
3716
+ {
3717
+ if !state.allows_non_functional_pseudo_classes() {
3718
+ return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3719
+ }
3720
+
3721
+ if state.allows_tree_structural_pseudo_classes() {
3722
+ // If a descendant pseudo of a pseudo-element root has no other siblings, then :only-child
3723
+ // matches that pseudo. Note that we don't accept other tree structural pseudo classes in
3724
+ // this case (to match other browsers). And the spec mentions only `:only-child` as well.
3725
+ // https://drafts.csswg.org/css-view-transitions-1/#pseudo-root
3726
+ if state.allows_only_child_pseudo_class_only() {
3727
+ if name.eq_ignore_ascii_case("only-child") {
3728
+ return Ok(Component::Nth(NthSelectorData::only(
3729
+ /* of_type = */ false,
3730
+ )));
3731
+ }
3732
+ // Other non-functional pseudo classes are not allowed.
3733
+ // FIXME: Perhaps we can refactor this, e.g. distinguish tree-structural pseudo classes
3734
+ // from other non-ts pseudo classes. Otherwise, this special case looks weird.
3735
+ return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3736
+ }
3737
+
3738
+ match_ignore_ascii_case! { &name,
3739
+ "first-child" => return Ok(Component::Nth(NthSelectorData::first(/* of_type = */ false))),
3740
+ "last-child" => return Ok(Component::Nth(NthSelectorData::last(/* of_type = */ false))),
3741
+ "only-child" => return Ok(Component::Nth(NthSelectorData::only(/* of_type = */ false))),
3742
+ "root" => return Ok(Component::Root),
3743
+ "empty" => return Ok(Component::Empty),
3744
+ "scope" => return Ok(Component::Scope),
3745
+ "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
3746
+ "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(/* of_type = */ true))),
3747
+ "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(/* of_type = */ true))),
3748
+ "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(/* of_type = */ true))),
3749
+ _ => {},
3750
+ }
3751
+ }
3752
+
3753
+ let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
3754
+ if state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3755
+ && !pseudo_class.is_user_action_state()
3756
+ {
3757
+ return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3758
+ }
3759
+ Ok(Component::NonTSPseudoClass(pseudo_class))
3760
+ }
3761
+
3762
+ // NB: pub module in order to access the DummyParser
3763
+ #[cfg(test)]
3764
+ pub mod tests {
3765
+ use super::*;
3766
+ use crate::builder::SelectorFlags;
3767
+ use crate::parser;
3768
+ use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss};
3769
+ use std::collections::HashMap;
3770
+ use std::fmt;
3771
+
3772
+ #[derive(Clone, Debug, Eq, PartialEq)]
3773
+ pub enum PseudoClass {
3774
+ Hover,
3775
+ Active,
3776
+ Lang(String),
3777
+ }
3778
+
3779
+ #[derive(Clone, Debug, Eq, PartialEq)]
3780
+ pub enum PseudoElement {
3781
+ Before,
3782
+ After,
3783
+ Marker,
3784
+ DetailsContent,
3785
+ Highlight(String),
3786
+ }
3787
+
3788
+ impl parser::PseudoElement for PseudoElement {
3789
+ type Impl = DummySelectorImpl;
3790
+
3791
+ fn accepts_state_pseudo_classes(&self) -> bool {
3792
+ true
3793
+ }
3794
+
3795
+ fn valid_after_slotted(&self) -> bool {
3796
+ true
3797
+ }
3798
+
3799
+ fn valid_after_before_or_after(&self) -> bool {
3800
+ matches!(self, Self::Marker)
3801
+ }
3802
+
3803
+ fn is_before_or_after(&self) -> bool {
3804
+ matches!(self, Self::Before | Self::After)
3805
+ }
3806
+
3807
+ fn parses_as_element_backed(&self) -> bool {
3808
+ matches!(self, Self::DetailsContent)
3809
+ }
3810
+ }
3811
+
3812
+ impl parser::NonTSPseudoClass for PseudoClass {
3813
+ type Impl = DummySelectorImpl;
3814
+
3815
+ #[inline]
3816
+ fn is_active_or_hover(&self) -> bool {
3817
+ matches!(*self, PseudoClass::Active | PseudoClass::Hover)
3818
+ }
3819
+
3820
+ #[inline]
3821
+ fn is_user_action_state(&self) -> bool {
3822
+ self.is_active_or_hover()
3823
+ }
3824
+ }
3825
+
3826
+ impl ToCss for PseudoClass {
3827
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3828
+ where
3829
+ W: fmt::Write,
3830
+ {
3831
+ match *self {
3832
+ PseudoClass::Hover => dest.write_str(":hover"),
3833
+ PseudoClass::Active => dest.write_str(":active"),
3834
+ PseudoClass::Lang(ref lang) => {
3835
+ dest.write_str(":lang(")?;
3836
+ serialize_identifier(lang, dest)?;
3837
+ dest.write_char(')')
3838
+ },
3839
+ }
3840
+ }
3841
+ }
3842
+
3843
+ impl ToCss for PseudoElement {
3844
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3845
+ where
3846
+ W: fmt::Write,
3847
+ {
3848
+ match *self {
3849
+ PseudoElement::Before => dest.write_str("::before"),
3850
+ PseudoElement::After => dest.write_str("::after"),
3851
+ PseudoElement::Marker => dest.write_str("::marker"),
3852
+ PseudoElement::DetailsContent => dest.write_str("::details-content"),
3853
+ PseudoElement::Highlight(ref name) => {
3854
+ dest.write_str("::highlight(")?;
3855
+ serialize_identifier(&name, dest)?;
3856
+ dest.write_char(')')
3857
+ },
3858
+ }
3859
+ }
3860
+ }
3861
+
3862
+ #[derive(Clone, Debug, PartialEq)]
3863
+ pub struct DummySelectorImpl;
3864
+
3865
+ #[derive(Default)]
3866
+ pub struct DummyParser {
3867
+ default_ns: Option<DummyAtom>,
3868
+ ns_prefixes: HashMap<DummyAtom, DummyAtom>,
3869
+ }
3870
+
3871
+ impl DummyParser {
3872
+ fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
3873
+ DummyParser {
3874
+ default_ns: Some(default_ns),
3875
+ ns_prefixes: Default::default(),
3876
+ }
3877
+ }
3878
+ }
3879
+
3880
+ impl SelectorImpl for DummySelectorImpl {
3881
+ type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>;
3882
+ type AttrValue = DummyAttrValue;
3883
+ type Identifier = DummyAtom;
3884
+ type LocalName = DummyAtom;
3885
+ type NamespaceUrl = DummyAtom;
3886
+ type NamespacePrefix = DummyAtom;
3887
+ type BorrowedLocalName = DummyAtom;
3888
+ type BorrowedNamespaceUrl = DummyAtom;
3889
+ type NonTSPseudoClass = PseudoClass;
3890
+ type PseudoElement = PseudoElement;
3891
+ }
3892
+
3893
+ #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3894
+ pub struct DummyAttrValue(String);
3895
+
3896
+ impl ToCss for DummyAttrValue {
3897
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3898
+ where
3899
+ W: fmt::Write,
3900
+ {
3901
+ use std::fmt::Write;
3902
+
3903
+ dest.write_char('"')?;
3904
+ write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)?;
3905
+ dest.write_char('"')
3906
+ }
3907
+ }
3908
+
3909
+ impl<'a> From<&'a str> for DummyAttrValue {
3910
+ fn from(string: &'a str) -> Self {
3911
+ Self(string.into())
3912
+ }
3913
+ }
3914
+
3915
+ #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3916
+ pub struct DummyAtom(String);
3917
+
3918
+ impl ToCss for DummyAtom {
3919
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3920
+ where
3921
+ W: fmt::Write,
3922
+ {
3923
+ serialize_identifier(&self.0, dest)
3924
+ }
3925
+ }
3926
+
3927
+ impl From<String> for DummyAtom {
3928
+ fn from(string: String) -> Self {
3929
+ DummyAtom(string)
3930
+ }
3931
+ }
3932
+
3933
+ impl<'a> From<&'a str> for DummyAtom {
3934
+ fn from(string: &'a str) -> Self {
3935
+ DummyAtom(string.into())
3936
+ }
3937
+ }
3938
+
3939
+ impl PrecomputedHash for DummyAtom {
3940
+ fn precomputed_hash(&self) -> u32 {
3941
+ self.0.as_ptr() as u32
3942
+ }
3943
+ }
3944
+
3945
+ impl<'i> Parser<'i> for DummyParser {
3946
+ type Impl = DummySelectorImpl;
3947
+ type Error = SelectorParseErrorKind<'i>;
3948
+
3949
+ fn parse_slotted(&self) -> bool {
3950
+ true
3951
+ }
3952
+
3953
+ fn parse_nth_child_of(&self) -> bool {
3954
+ true
3955
+ }
3956
+
3957
+ fn parse_is_and_where(&self) -> bool {
3958
+ true
3959
+ }
3960
+
3961
+ fn parse_has(&self) -> bool {
3962
+ true
3963
+ }
3964
+
3965
+ fn parse_parent_selector(&self) -> bool {
3966
+ true
3967
+ }
3968
+
3969
+ fn parse_part(&self) -> bool {
3970
+ true
3971
+ }
3972
+
3973
+ fn parse_host(&self) -> bool {
3974
+ true
3975
+ }
3976
+
3977
+ fn parse_non_ts_pseudo_class(
3978
+ &self,
3979
+ location: SourceLocation,
3980
+ name: CowRcStr<'i>,
3981
+ ) -> Result<PseudoClass, SelectorParseError<'i>> {
3982
+ match_ignore_ascii_case! { &name,
3983
+ "hover" => return Ok(PseudoClass::Hover),
3984
+ "active" => return Ok(PseudoClass::Active),
3985
+ _ => {}
3986
+ }
3987
+ Err(
3988
+ location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
3989
+ name,
3990
+ )),
3991
+ )
3992
+ }
3993
+
3994
+ fn parse_non_ts_functional_pseudo_class<'t>(
3995
+ &self,
3996
+ name: CowRcStr<'i>,
3997
+ parser: &mut CssParser<'i, 't>,
3998
+ after_part: bool,
3999
+ ) -> Result<PseudoClass, SelectorParseError<'i>> {
4000
+ match_ignore_ascii_case! { &name,
4001
+ "lang" if !after_part => {
4002
+ let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
4003
+ return Ok(PseudoClass::Lang(lang));
4004
+ },
4005
+ _ => {}
4006
+ }
4007
+ Err(
4008
+ parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4009
+ name,
4010
+ )),
4011
+ )
4012
+ }
4013
+
4014
+ fn parse_pseudo_element(
4015
+ &self,
4016
+ location: SourceLocation,
4017
+ name: CowRcStr<'i>,
4018
+ ) -> Result<PseudoElement, SelectorParseError<'i>> {
4019
+ match_ignore_ascii_case! { &name,
4020
+ "before" => return Ok(PseudoElement::Before),
4021
+ "after" => return Ok(PseudoElement::After),
4022
+ "marker" => return Ok(PseudoElement::Marker),
4023
+ "details-content" => return Ok(PseudoElement::DetailsContent),
4024
+ _ => {}
4025
+ }
4026
+ Err(
4027
+ location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4028
+ name,
4029
+ )),
4030
+ )
4031
+ }
4032
+
4033
+ fn parse_functional_pseudo_element<'t>(
4034
+ &self,
4035
+ name: CowRcStr<'i>,
4036
+ parser: &mut CssParser<'i, 't>,
4037
+ ) -> Result<PseudoElement, SelectorParseError<'i>> {
4038
+ match_ignore_ascii_case! { &name,
4039
+ "highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
4040
+ _ => {}
4041
+ }
4042
+ Err(
4043
+ parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4044
+ name,
4045
+ )),
4046
+ )
4047
+ }
4048
+
4049
+ fn default_namespace(&self) -> Option<DummyAtom> {
4050
+ self.default_ns.clone()
4051
+ }
4052
+
4053
+ fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
4054
+ self.ns_prefixes.get(prefix).cloned()
4055
+ }
4056
+ }
4057
+
4058
+ fn parse<'i>(
4059
+ input: &'i str,
4060
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4061
+ parse_relative(input, ParseRelative::No)
4062
+ }
4063
+
4064
+ fn parse_relative<'i>(
4065
+ input: &'i str,
4066
+ parse_relative: ParseRelative,
4067
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4068
+ parse_ns_relative(input, &DummyParser::default(), parse_relative)
4069
+ }
4070
+
4071
+ fn parse_expected<'i, 'a>(
4072
+ input: &'i str,
4073
+ expected: Option<&'a str>,
4074
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4075
+ parse_ns_expected(input, &DummyParser::default(), expected)
4076
+ }
4077
+
4078
+ fn parse_relative_expected<'i, 'a>(
4079
+ input: &'i str,
4080
+ parse_relative: ParseRelative,
4081
+ expected: Option<&'a str>,
4082
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4083
+ parse_ns_relative_expected(input, &DummyParser::default(), parse_relative, expected)
4084
+ }
4085
+
4086
+ fn parse_ns<'i>(
4087
+ input: &'i str,
4088
+ parser: &DummyParser,
4089
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4090
+ parse_ns_relative(input, parser, ParseRelative::No)
4091
+ }
4092
+
4093
+ fn parse_ns_relative<'i>(
4094
+ input: &'i str,
4095
+ parser: &DummyParser,
4096
+ parse_relative: ParseRelative,
4097
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4098
+ parse_ns_relative_expected(input, parser, parse_relative, None)
4099
+ }
4100
+
4101
+ fn parse_ns_expected<'i, 'a>(
4102
+ input: &'i str,
4103
+ parser: &DummyParser,
4104
+ expected: Option<&'a str>,
4105
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4106
+ parse_ns_relative_expected(input, parser, ParseRelative::No, expected)
4107
+ }
4108
+
4109
+ fn parse_ns_relative_expected<'i, 'a>(
4110
+ input: &'i str,
4111
+ parser: &DummyParser,
4112
+ parse_relative: ParseRelative,
4113
+ expected: Option<&'a str>,
4114
+ ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4115
+ let mut parser_input = ParserInput::new(input);
4116
+ let result = SelectorList::parse(
4117
+ parser,
4118
+ &mut CssParser::new(&mut parser_input),
4119
+ parse_relative,
4120
+ );
4121
+ if let Ok(ref selectors) = result {
4122
+ // We can't assume that the serialized parsed selector will equal
4123
+ // the input; for example, if there is no default namespace, '*|foo'
4124
+ // should serialize to 'foo'.
4125
+ assert_eq!(
4126
+ selectors.to_css_string(),
4127
+ match expected {
4128
+ Some(x) => x,
4129
+ None => input,
4130
+ }
4131
+ );
4132
+ }
4133
+ result
4134
+ }
4135
+
4136
+ fn specificity(a: u32, b: u32, c: u32) -> u32 {
4137
+ a << 20 | b << 10 | c
4138
+ }
4139
+
4140
+ #[test]
4141
+ fn test_empty() {
4142
+ let mut input = ParserInput::new(":empty");
4143
+ let list = SelectorList::parse(
4144
+ &DummyParser::default(),
4145
+ &mut CssParser::new(&mut input),
4146
+ ParseRelative::No,
4147
+ );
4148
+ assert!(list.is_ok());
4149
+ }
4150
+
4151
+ const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
4152
+ const SVG: &str = "http://www.w3.org/2000/svg";
4153
+
4154
+ #[test]
4155
+ fn test_parsing() {
4156
+ assert!(parse("").is_err());
4157
+ assert!(parse(":lang(4)").is_err());
4158
+ assert!(parse(":lang(en US)").is_err());
4159
+ assert_eq!(
4160
+ parse("EeÉ"),
4161
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4162
+ vec![Component::LocalName(LocalName {
4163
+ name: DummyAtom::from("EeÉ"),
4164
+ lower_name: DummyAtom::from("eeÉ"),
4165
+ })],
4166
+ specificity(0, 0, 1),
4167
+ SelectorFlags::empty(),
4168
+ )]))
4169
+ );
4170
+ assert_eq!(
4171
+ parse("|e"),
4172
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4173
+ vec![
4174
+ Component::ExplicitNoNamespace,
4175
+ Component::LocalName(LocalName {
4176
+ name: DummyAtom::from("e"),
4177
+ lower_name: DummyAtom::from("e"),
4178
+ }),
4179
+ ],
4180
+ specificity(0, 0, 1),
4181
+ SelectorFlags::empty(),
4182
+ )]))
4183
+ );
4184
+ // When the default namespace is not set, *| should be elided.
4185
+ // https://github.com/servo/servo/pull/17537
4186
+ assert_eq!(
4187
+ parse_expected("*|e", Some("e")),
4188
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4189
+ vec![Component::LocalName(LocalName {
4190
+ name: DummyAtom::from("e"),
4191
+ lower_name: DummyAtom::from("e"),
4192
+ })],
4193
+ specificity(0, 0, 1),
4194
+ SelectorFlags::empty(),
4195
+ )]))
4196
+ );
4197
+ // When the default namespace is set, *| should _not_ be elided (as foo
4198
+ // is no longer equivalent to *|foo--the former is only for foo in the
4199
+ // default namespace).
4200
+ // https://github.com/servo/servo/issues/16020
4201
+ assert_eq!(
4202
+ parse_ns(
4203
+ "*|e",
4204
+ &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4205
+ ),
4206
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4207
+ vec![
4208
+ Component::ExplicitAnyNamespace,
4209
+ Component::LocalName(LocalName {
4210
+ name: DummyAtom::from("e"),
4211
+ lower_name: DummyAtom::from("e"),
4212
+ }),
4213
+ ],
4214
+ specificity(0, 0, 1),
4215
+ SelectorFlags::empty(),
4216
+ )]))
4217
+ );
4218
+ assert_eq!(
4219
+ parse("*"),
4220
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4221
+ vec![Component::ExplicitUniversalType],
4222
+ specificity(0, 0, 0),
4223
+ SelectorFlags::empty(),
4224
+ )]))
4225
+ );
4226
+ assert_eq!(
4227
+ parse("|*"),
4228
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4229
+ vec![
4230
+ Component::ExplicitNoNamespace,
4231
+ Component::ExplicitUniversalType,
4232
+ ],
4233
+ specificity(0, 0, 0),
4234
+ SelectorFlags::empty(),
4235
+ )]))
4236
+ );
4237
+ assert_eq!(
4238
+ parse_expected("*|*", Some("*")),
4239
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4240
+ vec![Component::ExplicitUniversalType],
4241
+ specificity(0, 0, 0),
4242
+ SelectorFlags::empty(),
4243
+ )]))
4244
+ );
4245
+ assert_eq!(
4246
+ parse_ns(
4247
+ "*|*",
4248
+ &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4249
+ ),
4250
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4251
+ vec![
4252
+ Component::ExplicitAnyNamespace,
4253
+ Component::ExplicitUniversalType,
4254
+ ],
4255
+ specificity(0, 0, 0),
4256
+ SelectorFlags::empty(),
4257
+ )]))
4258
+ );
4259
+ assert_eq!(
4260
+ parse(".foo:lang(en-US)"),
4261
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4262
+ vec![
4263
+ Component::Class(DummyAtom::from("foo")),
4264
+ Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
4265
+ ],
4266
+ specificity(0, 2, 0),
4267
+ SelectorFlags::empty(),
4268
+ )]))
4269
+ );
4270
+ assert_eq!(
4271
+ parse("#bar"),
4272
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4273
+ vec![Component::ID(DummyAtom::from("bar"))],
4274
+ specificity(1, 0, 0),
4275
+ SelectorFlags::empty(),
4276
+ )]))
4277
+ );
4278
+ assert_eq!(
4279
+ parse("e.foo#bar"),
4280
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4281
+ vec![
4282
+ Component::LocalName(LocalName {
4283
+ name: DummyAtom::from("e"),
4284
+ lower_name: DummyAtom::from("e"),
4285
+ }),
4286
+ Component::Class(DummyAtom::from("foo")),
4287
+ Component::ID(DummyAtom::from("bar")),
4288
+ ],
4289
+ specificity(1, 1, 1),
4290
+ SelectorFlags::empty(),
4291
+ )]))
4292
+ );
4293
+ assert_eq!(
4294
+ parse("e.foo #bar"),
4295
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4296
+ vec![
4297
+ Component::LocalName(LocalName {
4298
+ name: DummyAtom::from("e"),
4299
+ lower_name: DummyAtom::from("e"),
4300
+ }),
4301
+ Component::Class(DummyAtom::from("foo")),
4302
+ Component::Combinator(Combinator::Descendant),
4303
+ Component::ID(DummyAtom::from("bar")),
4304
+ ],
4305
+ specificity(1, 1, 1),
4306
+ SelectorFlags::empty(),
4307
+ )]))
4308
+ );
4309
+ // Default namespace does not apply to attribute selectors
4310
+ // https://github.com/mozilla/servo/pull/1652
4311
+ let mut parser = DummyParser::default();
4312
+ assert_eq!(
4313
+ parse_ns("[Foo]", &parser),
4314
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4315
+ vec![Component::AttributeInNoNamespaceExists {
4316
+ local_name: DummyAtom::from("Foo"),
4317
+ local_name_lower: DummyAtom::from("foo"),
4318
+ }],
4319
+ specificity(0, 1, 0),
4320
+ SelectorFlags::empty(),
4321
+ )]))
4322
+ );
4323
+ assert!(parse_ns("svg|circle", &parser).is_err());
4324
+ parser
4325
+ .ns_prefixes
4326
+ .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
4327
+ assert_eq!(
4328
+ parse_ns("svg|circle", &parser),
4329
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4330
+ vec![
4331
+ Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4332
+ Component::LocalName(LocalName {
4333
+ name: DummyAtom::from("circle"),
4334
+ lower_name: DummyAtom::from("circle"),
4335
+ }),
4336
+ ],
4337
+ specificity(0, 0, 1),
4338
+ SelectorFlags::empty(),
4339
+ )]))
4340
+ );
4341
+ assert_eq!(
4342
+ parse_ns("svg|*", &parser),
4343
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4344
+ vec![
4345
+ Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4346
+ Component::ExplicitUniversalType,
4347
+ ],
4348
+ specificity(0, 0, 0),
4349
+ SelectorFlags::empty(),
4350
+ )]))
4351
+ );
4352
+ // Default namespace does not apply to attribute selectors
4353
+ // https://github.com/mozilla/servo/pull/1652
4354
+ // but it does apply to implicit type selectors
4355
+ // https://github.com/servo/rust-selectors/pull/82
4356
+ parser.default_ns = Some(MATHML.into());
4357
+ assert_eq!(
4358
+ parse_ns("[Foo]", &parser),
4359
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4360
+ vec![
4361
+ Component::DefaultNamespace(MATHML.into()),
4362
+ Component::AttributeInNoNamespaceExists {
4363
+ local_name: DummyAtom::from("Foo"),
4364
+ local_name_lower: DummyAtom::from("foo"),
4365
+ },
4366
+ ],
4367
+ specificity(0, 1, 0),
4368
+ SelectorFlags::empty(),
4369
+ )]))
4370
+ );
4371
+ // Default namespace does apply to type selectors
4372
+ assert_eq!(
4373
+ parse_ns("e", &parser),
4374
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4375
+ vec![
4376
+ Component::DefaultNamespace(MATHML.into()),
4377
+ Component::LocalName(LocalName {
4378
+ name: DummyAtom::from("e"),
4379
+ lower_name: DummyAtom::from("e"),
4380
+ }),
4381
+ ],
4382
+ specificity(0, 0, 1),
4383
+ SelectorFlags::empty(),
4384
+ )]))
4385
+ );
4386
+ assert_eq!(
4387
+ parse_ns("*", &parser),
4388
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4389
+ vec![
4390
+ Component::DefaultNamespace(MATHML.into()),
4391
+ Component::ExplicitUniversalType,
4392
+ ],
4393
+ specificity(0, 0, 0),
4394
+ SelectorFlags::empty(),
4395
+ )]))
4396
+ );
4397
+ assert_eq!(
4398
+ parse_ns("*|*", &parser),
4399
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4400
+ vec![
4401
+ Component::ExplicitAnyNamespace,
4402
+ Component::ExplicitUniversalType,
4403
+ ],
4404
+ specificity(0, 0, 0),
4405
+ SelectorFlags::empty(),
4406
+ )]))
4407
+ );
4408
+ // Default namespace applies to universal and type selectors inside :not and :matches,
4409
+ // but not otherwise.
4410
+ assert_eq!(
4411
+ parse_ns(":not(.cl)", &parser),
4412
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4413
+ vec![
4414
+ Component::DefaultNamespace(MATHML.into()),
4415
+ Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4416
+ vec![Component::Class(DummyAtom::from("cl"))],
4417
+ specificity(0, 1, 0),
4418
+ SelectorFlags::empty(),
4419
+ )])),
4420
+ ],
4421
+ specificity(0, 1, 0),
4422
+ SelectorFlags::empty(),
4423
+ )]))
4424
+ );
4425
+ assert_eq!(
4426
+ parse_ns(":not(*)", &parser),
4427
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4428
+ vec![
4429
+ Component::DefaultNamespace(MATHML.into()),
4430
+ Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4431
+ vec![
4432
+ Component::DefaultNamespace(MATHML.into()),
4433
+ Component::ExplicitUniversalType,
4434
+ ],
4435
+ specificity(0, 0, 0),
4436
+ SelectorFlags::empty(),
4437
+ )]),),
4438
+ ],
4439
+ specificity(0, 0, 0),
4440
+ SelectorFlags::empty(),
4441
+ )]))
4442
+ );
4443
+ assert_eq!(
4444
+ parse_ns(":not(e)", &parser),
4445
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4446
+ vec![
4447
+ Component::DefaultNamespace(MATHML.into()),
4448
+ Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4449
+ vec![
4450
+ Component::DefaultNamespace(MATHML.into()),
4451
+ Component::LocalName(LocalName {
4452
+ name: DummyAtom::from("e"),
4453
+ lower_name: DummyAtom::from("e"),
4454
+ }),
4455
+ ],
4456
+ specificity(0, 0, 1),
4457
+ SelectorFlags::empty(),
4458
+ )])),
4459
+ ],
4460
+ specificity(0, 0, 1),
4461
+ SelectorFlags::empty(),
4462
+ )]))
4463
+ );
4464
+ assert_eq!(
4465
+ parse("[attr|=\"foo\"]"),
4466
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4467
+ vec![Component::AttributeInNoNamespace {
4468
+ local_name: DummyAtom::from("attr"),
4469
+ operator: AttrSelectorOperator::DashMatch,
4470
+ value: DummyAttrValue::from("foo"),
4471
+ case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
4472
+ }],
4473
+ specificity(0, 1, 0),
4474
+ SelectorFlags::empty(),
4475
+ )]))
4476
+ );
4477
+ // https://github.com/mozilla/servo/issues/1723
4478
+ assert_eq!(
4479
+ parse("::before"),
4480
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4481
+ vec![
4482
+ Component::Combinator(Combinator::PseudoElement),
4483
+ Component::PseudoElement(PseudoElement::Before),
4484
+ ],
4485
+ specificity(0, 0, 1),
4486
+ SelectorFlags::HAS_PSEUDO,
4487
+ )]))
4488
+ );
4489
+ assert_eq!(
4490
+ parse("::before:hover"),
4491
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4492
+ vec![
4493
+ Component::Combinator(Combinator::PseudoElement),
4494
+ Component::PseudoElement(PseudoElement::Before),
4495
+ Component::NonTSPseudoClass(PseudoClass::Hover),
4496
+ ],
4497
+ specificity(0, 1, 1),
4498
+ SelectorFlags::HAS_PSEUDO,
4499
+ )]))
4500
+ );
4501
+ assert_eq!(
4502
+ parse("::before:hover:hover"),
4503
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4504
+ vec![
4505
+ Component::Combinator(Combinator::PseudoElement),
4506
+ Component::PseudoElement(PseudoElement::Before),
4507
+ Component::NonTSPseudoClass(PseudoClass::Hover),
4508
+ Component::NonTSPseudoClass(PseudoClass::Hover),
4509
+ ],
4510
+ specificity(0, 2, 1),
4511
+ SelectorFlags::HAS_PSEUDO,
4512
+ )]))
4513
+ );
4514
+ assert!(parse("::before:hover:lang(foo)").is_err());
4515
+ assert!(parse("::before:hover .foo").is_err());
4516
+ assert!(parse("::before .foo").is_err());
4517
+ assert!(parse("::before ~ bar").is_err());
4518
+ assert!(parse("::before:active").is_ok());
4519
+
4520
+ // https://github.com/servo/servo/issues/15335
4521
+ assert!(parse(":: before").is_err());
4522
+ assert_eq!(
4523
+ parse("div ::after"),
4524
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4525
+ vec![
4526
+ Component::LocalName(LocalName {
4527
+ name: DummyAtom::from("div"),
4528
+ lower_name: DummyAtom::from("div"),
4529
+ }),
4530
+ Component::Combinator(Combinator::Descendant),
4531
+ Component::Combinator(Combinator::PseudoElement),
4532
+ Component::PseudoElement(PseudoElement::After),
4533
+ ],
4534
+ specificity(0, 0, 2),
4535
+ SelectorFlags::HAS_PSEUDO,
4536
+ )]))
4537
+ );
4538
+ assert_eq!(
4539
+ parse("#d1 > .ok"),
4540
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4541
+ vec![
4542
+ Component::ID(DummyAtom::from("d1")),
4543
+ Component::Combinator(Combinator::Child),
4544
+ Component::Class(DummyAtom::from("ok")),
4545
+ ],
4546
+ specificity(1, 1, 0),
4547
+ SelectorFlags::empty(),
4548
+ )]))
4549
+ );
4550
+ parser.default_ns = None;
4551
+ assert!(parse(":not(#provel.old)").is_ok());
4552
+ assert!(parse(":not(#provel > old)").is_ok());
4553
+ assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
4554
+ // https://github.com/servo/servo/issues/16017
4555
+ assert_eq!(
4556
+ parse_ns(":not(*)", &parser),
4557
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4558
+ vec![Component::Negation(SelectorList::from_vec(vec![
4559
+ Selector::from_vec(
4560
+ vec![Component::ExplicitUniversalType],
4561
+ specificity(0, 0, 0),
4562
+ SelectorFlags::empty(),
4563
+ )
4564
+ ]))],
4565
+ specificity(0, 0, 0),
4566
+ SelectorFlags::empty(),
4567
+ )]))
4568
+ );
4569
+ assert_eq!(
4570
+ parse_ns(":not(|*)", &parser),
4571
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4572
+ vec![Component::Negation(SelectorList::from_vec(vec![
4573
+ Selector::from_vec(
4574
+ vec![
4575
+ Component::ExplicitNoNamespace,
4576
+ Component::ExplicitUniversalType,
4577
+ ],
4578
+ specificity(0, 0, 0),
4579
+ SelectorFlags::empty(),
4580
+ )
4581
+ ]))],
4582
+ specificity(0, 0, 0),
4583
+ SelectorFlags::empty(),
4584
+ )]))
4585
+ );
4586
+ // *| should be elided if there is no default namespace.
4587
+ // https://github.com/servo/servo/pull/17537
4588
+ assert_eq!(
4589
+ parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
4590
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4591
+ vec![Component::Negation(SelectorList::from_vec(vec![
4592
+ Selector::from_vec(
4593
+ vec![Component::ExplicitUniversalType],
4594
+ specificity(0, 0, 0),
4595
+ SelectorFlags::empty(),
4596
+ )
4597
+ ]))],
4598
+ specificity(0, 0, 0),
4599
+ SelectorFlags::empty(),
4600
+ )]))
4601
+ );
4602
+
4603
+ assert!(parse("::highlight(foo)").is_ok());
4604
+
4605
+ assert!(parse("::slotted()").is_err());
4606
+ assert!(parse("::slotted(div)").is_ok());
4607
+ assert!(parse("::slotted(div).foo").is_err());
4608
+ assert!(parse("::slotted(div + bar)").is_err());
4609
+ assert!(parse("::slotted(div) + foo").is_err());
4610
+
4611
+ assert!(parse("::part()").is_err());
4612
+ assert!(parse("::part(42)").is_err());
4613
+ assert!(parse("::part(foo bar)").is_ok());
4614
+ assert!(parse("::part(foo):hover").is_ok());
4615
+ assert!(parse("::part(foo) + bar").is_err());
4616
+
4617
+ assert!(parse("div ::slotted(div)").is_ok());
4618
+ assert!(parse("div + slot::slotted(div)").is_ok());
4619
+ assert!(parse("div + slot::slotted(div.foo)").is_ok());
4620
+ assert!(parse("slot::slotted(div,foo)::first-line").is_err());
4621
+ assert!(parse("::slotted(div)::before").is_ok());
4622
+ assert!(parse("slot::slotted(div,foo)").is_err());
4623
+
4624
+ assert!(parse("foo:where()").is_ok());
4625
+ assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
4626
+ assert!(parse("foo:where(::before)").is_ok());
4627
+ }
4628
+
4629
+ #[test]
4630
+ fn parent_selector() {
4631
+ assert!(parse("foo &").is_ok());
4632
+ assert_eq!(
4633
+ parse("#foo &.bar"),
4634
+ Ok(SelectorList::from_vec(vec![Selector::from_vec(
4635
+ vec![
4636
+ Component::ID(DummyAtom::from("foo")),
4637
+ Component::Combinator(Combinator::Descendant),
4638
+ Component::ParentSelector,
4639
+ Component::Class(DummyAtom::from("bar")),
4640
+ ],
4641
+ specificity(1, 1, 0),
4642
+ SelectorFlags::HAS_PARENT
4643
+ )]))
4644
+ );
4645
+
4646
+ let parent = parse(".bar, div .baz").unwrap();
4647
+ let child = parse("#foo &.bar").unwrap();
4648
+ assert_eq!(
4649
+ child.replace_parent_selector(&parent),
4650
+ parse("#foo :is(.bar, div .baz).bar").unwrap()
4651
+ );
4652
+
4653
+ let has_child = parse("#foo:has(&.bar)").unwrap();
4654
+ assert_eq!(
4655
+ has_child.replace_parent_selector(&parent),
4656
+ parse("#foo:has(:is(.bar, div .baz).bar)").unwrap()
4657
+ );
4658
+
4659
+ let child =
4660
+ parse_relative_expected("#foo", ParseRelative::ForNesting, Some("& #foo")).unwrap();
4661
+ assert_eq!(
4662
+ child.replace_parent_selector(&parent),
4663
+ parse(":is(.bar, div .baz) #foo").unwrap()
4664
+ );
4665
+
4666
+ let child =
4667
+ parse_relative_expected("+ #foo", ParseRelative::ForNesting, Some("& + #foo")).unwrap();
4668
+ assert_eq!(child, parse("& + #foo").unwrap());
4669
+ }
4670
+
4671
+ #[test]
4672
+ fn test_pseudo_iter() {
4673
+ let list = parse("q::before").unwrap();
4674
+ let selector = &list.slice()[0];
4675
+ assert!(!selector.is_universal());
4676
+ let mut iter = selector.iter();
4677
+ assert_eq!(
4678
+ iter.next(),
4679
+ Some(&Component::PseudoElement(PseudoElement::Before))
4680
+ );
4681
+ assert_eq!(iter.next(), None);
4682
+ let combinator = iter.next_sequence();
4683
+ assert_eq!(combinator, Some(Combinator::PseudoElement));
4684
+ assert_eq!(
4685
+ iter.next(),
4686
+ Some(&Component::LocalName(LocalName {
4687
+ name: DummyAtom::from("q"),
4688
+ lower_name: DummyAtom::from("q"),
4689
+ }))
4690
+ );
4691
+ assert_eq!(iter.next(), None);
4692
+ assert_eq!(iter.next_sequence(), None);
4693
+ }
4694
+
4695
+ #[test]
4696
+ fn test_pseudo_before_marker() {
4697
+ let list = parse("::before::marker").unwrap();
4698
+ let selector = &list.slice()[0];
4699
+ let mut iter = selector.iter();
4700
+ assert_eq!(
4701
+ iter.next(),
4702
+ Some(&Component::PseudoElement(PseudoElement::Marker))
4703
+ );
4704
+ assert_eq!(iter.next(), None);
4705
+ let combinator = iter.next_sequence();
4706
+ assert_eq!(combinator, Some(Combinator::PseudoElement));
4707
+ assert_eq!(
4708
+ iter.next(),
4709
+ Some(&Component::PseudoElement(PseudoElement::Before))
4710
+ );
4711
+ assert_eq!(iter.next(), None);
4712
+ let combinator = iter.next_sequence();
4713
+ assert_eq!(combinator, Some(Combinator::PseudoElement));
4714
+ assert_eq!(iter.next(), None);
4715
+ assert_eq!(iter.next_sequence(), None);
4716
+ }
4717
+
4718
+ #[test]
4719
+ fn test_pseudo_duplicate_before_after_or_marker() {
4720
+ assert!(parse("::before::before").is_err());
4721
+ assert!(parse("::after::after").is_err());
4722
+ assert!(parse("::marker::marker").is_err());
4723
+ }
4724
+
4725
+ #[test]
4726
+ fn test_pseudo_on_element_backed_pseudo() {
4727
+ let list = parse("::details-content::before").unwrap();
4728
+ let selector = &list.slice()[0];
4729
+ let mut iter = selector.iter();
4730
+ assert_eq!(
4731
+ iter.next(),
4732
+ Some(&Component::PseudoElement(PseudoElement::Before))
4733
+ );
4734
+ assert_eq!(iter.next(), None);
4735
+ let combinator = iter.next_sequence();
4736
+ assert_eq!(combinator, Some(Combinator::PseudoElement));
4737
+ assert_eq!(
4738
+ iter.next(),
4739
+ Some(&Component::PseudoElement(PseudoElement::DetailsContent))
4740
+ );
4741
+ assert_eq!(iter.next(), None);
4742
+ let combinator = iter.next_sequence();
4743
+ assert_eq!(combinator, Some(Combinator::PseudoElement));
4744
+ assert_eq!(iter.next(), None);
4745
+ assert_eq!(iter.next_sequence(), None);
4746
+ }
4747
+
4748
+ #[test]
4749
+ fn test_universal() {
4750
+ let list = parse_ns(
4751
+ "*|*::before",
4752
+ &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
4753
+ )
4754
+ .unwrap();
4755
+ let selector = &list.slice()[0];
4756
+ assert!(selector.is_universal());
4757
+ }
4758
+
4759
+ #[test]
4760
+ fn test_empty_pseudo_iter() {
4761
+ let list = parse("::before").unwrap();
4762
+ let selector = &list.slice()[0];
4763
+ assert!(selector.is_universal());
4764
+ let mut iter = selector.iter();
4765
+ assert_eq!(
4766
+ iter.next(),
4767
+ Some(&Component::PseudoElement(PseudoElement::Before))
4768
+ );
4769
+ assert_eq!(iter.next(), None);
4770
+ assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
4771
+ assert_eq!(iter.next(), None);
4772
+ assert_eq!(iter.next_sequence(), None);
4773
+ }
4774
+
4775
+ #[test]
4776
+ fn test_parse_implicit_scope() {
4777
+ assert_eq!(
4778
+ parse_relative_expected(".foo", ParseRelative::ForScope, None).unwrap(),
4779
+ SelectorList::from_vec(vec![Selector::from_vec(
4780
+ vec![
4781
+ Component::ImplicitScope,
4782
+ Component::Combinator(Combinator::Descendant),
4783
+ Component::Class(DummyAtom::from("foo")),
4784
+ ],
4785
+ specificity(0, 1, 0),
4786
+ SelectorFlags::HAS_SCOPE,
4787
+ )])
4788
+ );
4789
+
4790
+ assert_eq!(
4791
+ parse_relative_expected(":scope .foo", ParseRelative::ForScope, None).unwrap(),
4792
+ SelectorList::from_vec(vec![Selector::from_vec(
4793
+ vec![
4794
+ Component::Scope,
4795
+ Component::Combinator(Combinator::Descendant),
4796
+ Component::Class(DummyAtom::from("foo")),
4797
+ ],
4798
+ specificity(0, 2, 0),
4799
+ SelectorFlags::HAS_SCOPE
4800
+ )])
4801
+ );
4802
+
4803
+ assert_eq!(
4804
+ parse_relative_expected("> .foo", ParseRelative::ForScope, Some("> .foo")).unwrap(),
4805
+ SelectorList::from_vec(vec![Selector::from_vec(
4806
+ vec![
4807
+ Component::ImplicitScope,
4808
+ Component::Combinator(Combinator::Child),
4809
+ Component::Class(DummyAtom::from("foo")),
4810
+ ],
4811
+ specificity(0, 1, 0),
4812
+ SelectorFlags::HAS_SCOPE
4813
+ )])
4814
+ );
4815
+
4816
+ assert_eq!(
4817
+ parse_relative_expected(".foo :scope > .bar", ParseRelative::ForScope, None).unwrap(),
4818
+ SelectorList::from_vec(vec![Selector::from_vec(
4819
+ vec![
4820
+ Component::Class(DummyAtom::from("foo")),
4821
+ Component::Combinator(Combinator::Descendant),
4822
+ Component::Scope,
4823
+ Component::Combinator(Combinator::Child),
4824
+ Component::Class(DummyAtom::from("bar")),
4825
+ ],
4826
+ specificity(0, 3, 0),
4827
+ SelectorFlags::HAS_SCOPE
4828
+ )])
4829
+ );
4830
+ }
4831
+
4832
+ struct TestVisitor {
4833
+ seen: Vec<String>,
4834
+ }
4835
+
4836
+ impl SelectorVisitor for TestVisitor {
4837
+ type Impl = DummySelectorImpl;
4838
+
4839
+ fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
4840
+ let mut dest = String::new();
4841
+ s.to_css(&mut dest).unwrap();
4842
+ self.seen.push(dest);
4843
+ true
4844
+ }
4845
+ }
4846
+
4847
+ #[test]
4848
+ fn visitor() {
4849
+ let mut test_visitor = TestVisitor { seen: vec![] };
4850
+ parse(":not(:hover) ~ label").unwrap().slice()[0].visit(&mut test_visitor);
4851
+ assert!(test_visitor.seen.contains(&":hover".into()));
4852
+
4853
+ let mut test_visitor = TestVisitor { seen: vec![] };
4854
+ parse("::before:hover").unwrap().slice()[0].visit(&mut test_visitor);
4855
+ assert!(test_visitor.seen.contains(&":hover".into()));
4856
+ }
4857
+ }